blob: b81b7a6ef9c2d9fd1f0401b2f97b434e39aec9b1 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
Daniel Veillard7f7d1111999-09-22 09:46:25 +00009#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000010#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000011#else
Daniel Veillard151b1b01998-09-23 00:49:46 +000012#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000013#endif
14
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <string.h> /* for memset() only ! */
17
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
Daniel Veillard151b1b01998-09-23 00:49:46 +000024#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
Daniel Veillard361d8452000-04-03 19:48:13 +000028#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
31#include <libxml/entities.h>
32#include <libxml/valid.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000033
Daniel Veillarddd6b3671999-09-23 22:19:22 +000034static xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardcf461992000-03-14 18:30:20 +000035static xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +000036int oldXMLWDcompatibility = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +000037int xmlIndentTreeOutput = 0;
Daniel Veillardf5c2c871999-12-01 09:51:45 +000038xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
Daniel Veillard260a68f1998-08-13 03:39:55 +000039
Daniel Veillard15a8df41998-09-24 19:15:06 +000040static int xmlCompressMode = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +000041static int xmlCheckDTD = 1;
Daniel Veillarde41f2b72000-01-30 20:00:07 +000042int xmlSaveNoEmptyTags = 0;
Daniel Veillard3e6d2372000-03-04 11:39:43 +000043
44#define IS_BLANK(c) \
45 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
Daniel Veillard15a8df41998-09-24 19:15:06 +000046
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000047#define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \
Daniel Veillardcf461992000-03-14 18:30:20 +000048 xmlNodePtr ulccur = (n)->children; \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000049 if (ulccur == NULL) { \
50 (n)->last = NULL; \
51 } else { \
52 while (ulccur->next != NULL) ulccur = ulccur->next; \
53 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000054}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000055
Daniel Veillardad8f99d2000-01-15 14:20:03 +000056/* #define DEBUG_BUFFER */
57/* #define DEBUG_TREE */
58
Daniel Veillard260a68f1998-08-13 03:39:55 +000059/************************************************************************
60 * *
61 * Allocation and deallocation of basic structures *
62 * *
63 ************************************************************************/
64
Daniel Veillard97b58771998-10-20 06:14:16 +000065/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +000066 * xmlSetBufferAllocationScheme:
67 * @scheme: allocation method to use
68 *
69 * Set the buffer allocation method. Types are
70 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
71 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
72 * improves performance
73 */
74void
75xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
76 xmlBufferAllocScheme = scheme;
77}
78
79/**
80 * xmlGetBufferAllocationScheme:
81 *
82 * Types are
83 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
84 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
85 * improves performance
86 *
87 * Returns the current allocation scheme
88 */
89xmlBufferAllocationScheme
90xmlGetBufferAllocationScheme() {
91 return xmlBufferAllocScheme;
92}
93
94/**
Daniel Veillard97b58771998-10-20 06:14:16 +000095 * xmlUpgradeOldNs:
96 * @doc: a document pointer
97 *
98 * Upgrade old style Namespaces (PI) and move them to the root of the document.
Daniel Veillard260a68f1998-08-13 03:39:55 +000099 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000100void
101xmlUpgradeOldNs(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000102 xmlNsPtr cur;
103
104 if ((doc == NULL) || (doc->oldNs == NULL)) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000105 if (doc->children == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000106#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000107 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000108#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000109 return;
110 }
111
112 cur = doc->oldNs;
113 while (cur->next != NULL) {
114 cur->type = XML_LOCAL_NAMESPACE;
115 cur = cur->next;
116 }
117 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000118 cur->next = doc->children->nsDef;
119 doc->children->nsDef = doc->oldNs;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000120 doc->oldNs = NULL;
121}
122
Daniel Veillard97b58771998-10-20 06:14:16 +0000123/**
124 * xmlNewNs:
125 * @node: the element carrying the namespace
126 * @href: the URI associated
127 * @prefix: the prefix for the namespace
128 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000129 * Creation of a new Namespace. This function will refuse to create
130 * a namespace with a similar prefix than an existing one present on this
131 * node.
132 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000133 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000134xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000135xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000136 xmlNsPtr cur;
137
138 if (href == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000139#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000140 fprintf(stderr, "xmlNewNs: href == NULL !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000141#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142 return(NULL);
143 }
144
145 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000146 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000147 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000148 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000149 if (cur == NULL) {
150 fprintf(stderr, "xmlNewNs : malloc failed\n");
151 return(NULL);
152 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000153 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000154 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000155
Daniel Veillard260a68f1998-08-13 03:39:55 +0000156 if (href != NULL)
157 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000158 if (prefix != NULL)
159 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000160
161 /*
162 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000163 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000164 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000165 if (node != NULL) {
166 if (node->nsDef == NULL) {
167 node->nsDef = cur;
168 } else {
169 xmlNsPtr prev = node->nsDef;
170
Daniel Veillard0142b842000-01-14 14:45:24 +0000171 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
172 (!xmlStrcmp(prev->prefix, cur->prefix))) {
173 xmlFreeNs(cur);
174 return(NULL);
175 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000176 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000177 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000178 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
179 (!xmlStrcmp(prev->prefix, cur->prefix))) {
180 xmlFreeNs(cur);
181 return(NULL);
182 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000183 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000184 prev->next = cur;
185 }
186 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 return(cur);
188}
189
Daniel Veillard97b58771998-10-20 06:14:16 +0000190/**
191 * xmlNewGlobalNs:
192 * @doc: the document carrying the namespace
193 * @href: the URI associated
194 * @prefix: the prefix for the namespace
195 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000196 * Creation of a Namespace, the old way using PI and without scoping
197 * DEPRECATED !!!
Daniel Veillard0142b842000-01-14 14:45:24 +0000198 * It now create a namespace on the root element of the document if found.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000199 * Returns NULL this functionnality had been removed
Daniel Veillard260a68f1998-08-13 03:39:55 +0000200 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000201xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000202xmlNewGlobalNs(xmlDocPtr doc, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000203 xmlNodePtr root;
204
205 xmlNsPtr cur;
206
207 root = xmlDocGetRootElement(doc);
208 if (root != NULL)
209 return(xmlNewNs(root, href, prefix));
210
211 /*
212 * if there is no root element yet, create an old Namespace type
213 * and it will be moved to the root at save time.
214 */
215 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
216 if (cur == NULL) {
217 fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
218 return(NULL);
219 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000220 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard0142b842000-01-14 14:45:24 +0000221 cur->type = XML_GLOBAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000222
Daniel Veillard0142b842000-01-14 14:45:24 +0000223 if (href != NULL)
224 cur->href = xmlStrdup(href);
Daniel Veillard0142b842000-01-14 14:45:24 +0000225 if (prefix != NULL)
226 cur->prefix = xmlStrdup(prefix);
Daniel Veillard0142b842000-01-14 14:45:24 +0000227
228 /*
229 * Add it at the end to preserve parsing order ...
230 */
Daniel Veillard0142b842000-01-14 14:45:24 +0000231 if (doc != NULL) {
232 if (doc->oldNs == NULL) {
233 doc->oldNs = cur;
234 } else {
235 xmlNsPtr prev = doc->oldNs;
236
237 while (prev->next != NULL) prev = prev->next;
238 prev->next = cur;
239 }
240 }
241
242 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000243}
244
Daniel Veillard97b58771998-10-20 06:14:16 +0000245/**
246 * xmlSetNs:
247 * @node: a node in the document
248 * @ns: a namespace pointer
249 *
250 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000251 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000252void
253xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000254 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000255#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000256 fprintf(stderr, "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000257#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000258 return;
259 }
260 node->ns = ns;
261}
262
Daniel Veillard97b58771998-10-20 06:14:16 +0000263/**
264 * xmlFreeNs:
265 * @cur: the namespace pointer
266 *
267 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000268 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000269void
270xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000271 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000272#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000273 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000274#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 return;
276 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000277 if (cur->href != NULL) xmlFree((char *) cur->href);
278 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000279 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000280 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000281}
282
Daniel Veillard97b58771998-10-20 06:14:16 +0000283/**
284 * xmlFreeNsList:
285 * @cur: the first namespace pointer
286 *
287 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000288 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000289void
290xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000291 xmlNsPtr next;
292 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000293#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000294 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000295#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000296 return;
297 }
298 while (cur != NULL) {
299 next = cur->next;
300 xmlFreeNs(cur);
301 cur = next;
302 }
303}
304
Daniel Veillard97b58771998-10-20 06:14:16 +0000305/**
306 * xmlNewDtd:
307 * @doc: the document pointer
308 * @name: the DTD name
309 * @ExternalID: the external ID
310 * @SystemID: the system ID
311 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000312 * Creation of a new DTD for the external subset. To create an
313 * internal subset, use xmlCreateIntSubset().
314 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000315 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000316 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000317xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000318xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
319 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000320 xmlDtdPtr cur;
321
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000322 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000323#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000324 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000325 /* !!! */ (char *) name, doc->name,
326 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000327#endif
328 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000329 }
330
331 /*
332 * Allocate a new DTD and fill the fields.
333 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000334 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000335 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000336 fprintf(stderr, "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000337 return(NULL);
338 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000339 memset(cur, 0 , sizeof(xmlDtd));
340 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000341
342 if (name != NULL)
343 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000344 if (ExternalID != NULL)
345 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000346 if (SystemID != NULL)
347 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000348 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000349 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000350 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000351
352 return(cur);
353}
354
355/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000356 * xmlGetIntSubset:
357 * @doc: the document pointer
358 *
359 * Get the internal subset of a document
360 * Returns a pointer to the DTD structure or NULL if not found
361 */
362
363xmlDtdPtr
364xmlGetIntSubset(xmlDocPtr doc) {
365 xmlNodePtr cur;
366
367 if (doc == NULL)
368 return(NULL);
369 cur = doc->children;
370 while (cur != NULL) {
371 if (cur->type == XML_DTD_NODE)
372 return((xmlDtdPtr) cur);
373 cur = cur->next;
374 }
375 return((xmlDtdPtr) doc->intSubset);
376}
377
378/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000379 * xmlCreateIntSubset:
380 * @doc: the document pointer
381 * @name: the DTD name
382 * @ExternalID: the external ID
383 * @SystemID: the system ID
384 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000385 * Create the internal subset of a document
386 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000387 */
388xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000389xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
390 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000391 xmlDtdPtr cur;
392
Daniel Veillardcf461992000-03-14 18:30:20 +0000393 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000394#ifdef DEBUG_TREE
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000395 fprintf(stderr,
396 "xmlCreateIntSubset(): document %s already have an internal subset\n",
397 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000398#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000399 return(NULL);
400 }
401
402 /*
403 * Allocate a new DTD and fill the fields.
404 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000405 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000406 if (cur == NULL) {
407 fprintf(stderr, "xmlNewDtd : malloc failed\n");
408 return(NULL);
409 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000410 memset(cur, 0, sizeof(xmlDtd));
411 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000412
413 if (name != NULL)
414 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415 if (ExternalID != NULL)
416 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417 if (SystemID != NULL)
418 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000419 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000420 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000421 cur->parent = doc;
422 cur->doc = doc;
423 if (doc->children == NULL) {
424 doc->children = (xmlNodePtr) cur;
425 doc->last = (xmlNodePtr) cur;
426 } else {
427 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000428
Daniel Veillardcf461992000-03-14 18:30:20 +0000429 prev = doc->last;
430 prev->next = (xmlNodePtr) cur;
431 cur->prev = prev;
432 doc->last = (xmlNodePtr) cur;
433 }
434 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000435 return(cur);
436}
437
Daniel Veillard97b58771998-10-20 06:14:16 +0000438/**
439 * xmlFreeDtd:
440 * @cur: the DTD structure to free up
441 *
442 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000443 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000444void
445xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000446 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000447#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000448 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000449#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 return;
451 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000452 if (cur->children != NULL) {
453 xmlNodePtr next, c = cur->children;
454
455 /*
456 * Cleanup all the DTD comments they are not in the Dtd
457 * indexes.
458 */
459 while (c != NULL) {
460 next = c->next;
461 if (c->type == XML_COMMENT_NODE) {
462 xmlUnlinkNode(c);
463 xmlFreeNode(c);
464 }
465 c = next;
466 }
467 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000468 if (cur->name != NULL) xmlFree((char *) cur->name);
469 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
470 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000471 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000472 if (cur->notations != NULL)
473 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000474
Daniel Veillard260a68f1998-08-13 03:39:55 +0000475 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000476 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000477 if (cur->attributes != NULL)
478 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000479 if (cur->entities != NULL)
480 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000481
Daniel Veillard260a68f1998-08-13 03:39:55 +0000482 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000483 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000484}
485
Daniel Veillard97b58771998-10-20 06:14:16 +0000486/**
487 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000488 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000489 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000490 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000491 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000492xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000493xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000494 xmlDocPtr cur;
495
496 if (version == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000497#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000498 fprintf(stderr, "xmlNewDoc : version == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000499#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000500 return(NULL);
501 }
502
503 /*
504 * Allocate a new document and fill the fields.
505 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000506 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000507 if (cur == NULL) {
508 fprintf(stderr, "xmlNewDoc : malloc failed\n");
509 return(NULL);
510 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000511 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000512 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000513
Daniel Veillard260a68f1998-08-13 03:39:55 +0000514 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000515 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000516 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000517 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000518 return(cur);
519}
520
Daniel Veillard97b58771998-10-20 06:14:16 +0000521/**
522 * xmlFreeDoc:
523 * @cur: pointer to the document
524 * @:
525 *
526 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000527 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000528void
529xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000530 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000531#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000532 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000533#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000534 return;
535 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000536 if (cur->version != NULL) xmlFree((char *) cur->version);
537 if (cur->name != NULL) xmlFree((char *) cur->name);
538 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000539 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000540 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
541 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000542 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000543 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000544 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000545 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000546 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000547 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000548}
549
Daniel Veillard97b58771998-10-20 06:14:16 +0000550/**
Daniel Veillard16253641998-10-28 22:58:05 +0000551 * xmlStringLenGetNodeList:
552 * @doc: the document
553 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000554 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000555 *
556 * Parse the value string and build the node list associated. Should
557 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000558 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000559 */
560xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000561xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000562 xmlNodePtr ret = NULL, last = NULL;
563 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000564 xmlChar *val;
565 const xmlChar *cur = value;
566 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000567 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000568
569 if (value == NULL) return(NULL);
570
571 q = cur;
572 while ((*cur != 0) && (cur - value < len)) {
573 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000574 /*
575 * Save the current text.
576 */
Daniel Veillard16253641998-10-28 22:58:05 +0000577 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000578 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
579 xmlNodeAddContentLen(last, q, cur - q);
580 } else {
581 node = xmlNewDocTextLen(doc, q, cur - q);
582 if (node == NULL) return(ret);
583 if (last == NULL)
584 last = ret = node;
585 else {
586 last->next = node;
587 node->prev = last;
588 last = node;
589 }
Daniel Veillard16253641998-10-28 22:58:05 +0000590 }
591 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000592 /*
593 * Read the entity string
594 */
Daniel Veillard16253641998-10-28 22:58:05 +0000595 cur++;
596 q = cur;
597 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
598 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000599#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +0000600 fprintf(stderr,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000601 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000602#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000603 return(ret);
604 }
605 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000606 /*
607 * Predefined entities don't generate nodes
608 */
Daniel Veillard16253641998-10-28 22:58:05 +0000609 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000610 ent = xmlGetDocEntity(doc, val);
611 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000612 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000613 if (last == NULL) {
614 node = xmlNewDocText(doc, ent->content);
615 last = ret = node;
616 } else
617 xmlNodeAddContent(last, ent->content);
618
619 } else {
620 /*
621 * Create a new REFERENCE_REF node
622 */
623 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000624 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000625 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000626 return(ret);
627 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000628 if (last == NULL)
629 last = ret = node;
630 else {
631 last->next = node;
632 node->prev = last;
633 last = node;
634 }
Daniel Veillard16253641998-10-28 22:58:05 +0000635 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000636 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000637 }
638 cur++;
639 q = cur;
640 } else
641 cur++;
642 }
643 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000644 /*
645 * Handle the last piece of text.
646 */
647 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
648 xmlNodeAddContentLen(last, q, cur - q);
649 } else {
650 node = xmlNewDocTextLen(doc, q, cur - q);
651 if (node == NULL) return(ret);
652 if (last == NULL)
653 last = ret = node;
654 else {
655 last->next = node;
656 node->prev = last;
657 last = node;
658 }
Daniel Veillard16253641998-10-28 22:58:05 +0000659 }
660 }
661 return(ret);
662}
663
664/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000665 * xmlStringGetNodeList:
666 * @doc: the document
667 * @value: the value of the attribute
668 *
669 * Parse the value string and build the node list associated. Should
670 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000671 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000672 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000673xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000674xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000675 xmlNodePtr ret = NULL, last = NULL;
676 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000677 xmlChar *val;
678 const xmlChar *cur = value;
679 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000680 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000681
682 if (value == NULL) return(NULL);
683
684 q = cur;
685 while (*cur != 0) {
686 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000687 /*
688 * Save the current text.
689 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000690 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000691 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
692 xmlNodeAddContentLen(last, q, cur - q);
693 } else {
694 node = xmlNewDocTextLen(doc, q, cur - q);
695 if (node == NULL) return(ret);
696 if (last == NULL)
697 last = ret = node;
698 else {
699 last->next = node;
700 node->prev = last;
701 last = node;
702 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000703 }
704 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000705 /*
706 * Read the entity string
707 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000708 cur++;
709 q = cur;
710 while ((*cur != 0) && (*cur != ';')) cur++;
711 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000712#ifdef DEBUG_TREE
Daniel Veillardccb09631998-10-27 06:21:04 +0000713 fprintf(stderr,
714 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000715#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000716 return(ret);
717 }
718 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000719 /*
720 * Predefined entities don't generate nodes
721 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000722 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000723 ent = xmlGetDocEntity(doc, val);
724 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000725 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000726 if (last == NULL) {
727 node = xmlNewDocText(doc, ent->content);
728 last = ret = node;
729 } else
730 xmlNodeAddContent(last, ent->content);
731
732 } else {
733 /*
734 * Create a new REFERENCE_REF node
735 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000736 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000737 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000738 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000739 return(ret);
740 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000741 if (last == NULL)
742 last = ret = node;
743 else {
744 last->next = node;
745 node->prev = last;
746 last = node;
747 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000748 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000749 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000750 }
751 cur++;
752 q = cur;
753 } else
754 cur++;
755 }
756 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000757 /*
758 * Handle the last piece of text.
759 */
760 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
761 xmlNodeAddContentLen(last, q, cur - q);
762 } else {
763 node = xmlNewDocTextLen(doc, q, cur - q);
764 if (node == NULL) return(ret);
765 if (last == NULL)
766 last = ret = node;
767 else {
768 last->next = node;
769 node->prev = last;
770 last = node;
771 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000772 }
773 }
774 return(ret);
775}
776
777/**
778 * xmlNodeListGetString:
779 * @doc: the document
780 * @list: a Node list
781 * @inLine: should we replace entity contents or show their external form
782 *
783 * Returns the string equivalent to the text contained in the Node list
784 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000785 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000786 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000787xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000788xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000789 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000790 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000791 xmlEntityPtr ent;
792
793 if (list == NULL) return(NULL);
794
795 while (node != NULL) {
796 if (node->type == XML_TEXT_NODE) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000797 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000798#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000799 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000800#else
801 ret = xmlStrcat(ret, xmlBufferContent(node->content));
802#endif
803 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000804 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000805
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000806#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000807 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000808#else
809 buffer = xmlEncodeEntitiesReentrant(doc,
810 xmlBufferContent(node->content));
811#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000812 if (buffer != NULL) {
813 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000814 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000815 }
816 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000817 } else if (node->type == XML_ENTITY_REF_NODE) {
818 if (inLine) {
819 ent = xmlGetDocEntity(doc, node->name);
820 if (ent != NULL)
821 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000822 else {
823#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000824 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000825#else
826 ret = xmlStrcat(ret, xmlBufferContent(node->content));
827#endif
828 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000829 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000830 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000831 buf[0] = '&'; buf[1] = 0;
832 ret = xmlStrncat(ret, buf, 1);
833 ret = xmlStrcat(ret, node->name);
834 buf[0] = ';'; buf[1] = 0;
835 ret = xmlStrncat(ret, buf, 1);
836 }
837 }
838#if 0
839 else {
840 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
841 node->type);
842 }
843#endif
844 node = node->next;
845 }
846 return(ret);
847}
848
849/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000850 * xmlNodeListGetRawString:
851 * @doc: the document
852 * @list: a Node list
853 * @inLine: should we replace entity contents or show their external form
854 *
855 * Returns the string equivalent to the text contained in the Node list
856 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
857 * this function doesn't do any character encoding handling.
858 *
859 * Returns a pointer to the string copy, the calller must free it.
860 */
861xmlChar *
862xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
863 xmlNodePtr node = list;
864 xmlChar *ret = NULL;
865 xmlEntityPtr ent;
866
867 if (list == NULL) return(NULL);
868
869 while (node != NULL) {
870 if (node->type == XML_TEXT_NODE) {
871 if (inLine) {
872#ifndef XML_USE_BUFFER_CONTENT
873 ret = xmlStrcat(ret, node->content);
874#else
875 ret = xmlStrcat(ret, xmlBufferContent(node->content));
876#endif
877 } else {
878 xmlChar *buffer;
879
880#ifndef XML_USE_BUFFER_CONTENT
881 buffer = xmlEncodeSpecialChars(doc, node->content);
882#else
883 buffer = xmlEncodeSpecialChars(doc,
884 xmlBufferContent(node->content));
885#endif
886 if (buffer != NULL) {
887 ret = xmlStrcat(ret, buffer);
888 xmlFree(buffer);
889 }
890 }
891 } else if (node->type == XML_ENTITY_REF_NODE) {
892 if (inLine) {
893 ent = xmlGetDocEntity(doc, node->name);
894 if (ent != NULL)
895 ret = xmlStrcat(ret, ent->content);
896 else {
897#ifndef XML_USE_BUFFER_CONTENT
898 ret = xmlStrcat(ret, node->content);
899#else
900 ret = xmlStrcat(ret, xmlBufferContent(node->content));
901#endif
902 }
903 } else {
904 xmlChar buf[2];
905 buf[0] = '&'; buf[1] = 0;
906 ret = xmlStrncat(ret, buf, 1);
907 ret = xmlStrcat(ret, node->name);
908 buf[0] = ';'; buf[1] = 0;
909 ret = xmlStrncat(ret, buf, 1);
910 }
911 }
912#if 0
913 else {
914 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
915 node->type);
916 }
917#endif
918 node = node->next;
919 }
920 return(ret);
921}
922
923/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000924 * xmlNewProp:
925 * @node: the holding node
926 * @name: the name of the attribute
927 * @value: the value of the attribute
928 *
929 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000930 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000931 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000932xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000933xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000934 xmlAttrPtr cur;
935
936 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000937#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000938 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000939#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000940 return(NULL);
941 }
942
943 /*
944 * Allocate a new property and fill the fields.
945 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000946 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000947 if (cur == NULL) {
948 fprintf(stderr, "xmlNewProp : malloc failed\n");
949 return(NULL);
950 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000951 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000952 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000953
954 cur->parent = node;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000955 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000956 if (value != NULL) {
957 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000958 xmlNodePtr tmp;
959
Daniel Veillard51e3b151999-11-12 17:02:31 +0000960 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +0000961 cur->children = xmlStringGetNodeList(node->doc, buffer);
962 tmp = cur->children;
963 while (tmp != NULL) {
964 tmp->parent = (xmlNodePtr) cur;
965 if (tmp->next == NULL)
966 cur->last = tmp;
967 tmp = tmp->next;
968 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000969 xmlFree(buffer);
970 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000971
972 /*
973 * Add it at the end to preserve parsing order ...
974 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000975 if (node != NULL) {
976 if (node->properties == NULL) {
977 node->properties = cur;
978 } else {
979 xmlAttrPtr prev = node->properties;
980
981 while (prev->next != NULL) prev = prev->next;
982 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000983 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000984 }
985 }
986 return(cur);
987}
988
989/**
990 * xmlNewNsProp:
991 * @node: the holding node
992 * @ns: the namespace
993 * @name: the name of the attribute
994 * @value: the value of the attribute
995 *
996 * Create a new property tagged with a namespace and carried by a node.
997 * Returns a pointer to the attribute
998 */
999xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001000xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1001 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001002 xmlAttrPtr cur;
1003
1004 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001005#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001006 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001007#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001008 return(NULL);
1009 }
1010
1011 /*
1012 * Allocate a new property and fill the fields.
1013 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001014 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001015 if (cur == NULL) {
1016 fprintf(stderr, "xmlNewProp : malloc failed\n");
1017 return(NULL);
1018 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001019 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001020 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001021
1022 cur->parent = node;
1023 if (node != NULL)
1024 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001025 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001026 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001027 if (value != NULL) {
1028 xmlChar *buffer;
1029 xmlNodePtr tmp;
1030
1031 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
1032 cur->children = xmlStringGetNodeList(node->doc, buffer);
1033 tmp = cur->children;
1034 while (tmp != NULL) {
1035 tmp->parent = (xmlNodePtr) cur;
1036 if (tmp->next == NULL)
1037 cur->last = tmp;
1038 tmp = tmp->next;
1039 }
1040 xmlFree(buffer);
1041 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001042
1043 /*
1044 * Add it at the end to preserve parsing order ...
1045 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001046 if (node != NULL) {
1047 if (node->properties == NULL) {
1048 node->properties = cur;
1049 } else {
1050 xmlAttrPtr prev = node->properties;
1051
1052 while (prev->next != NULL) prev = prev->next;
1053 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001054 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001055 }
1056 }
1057 return(cur);
1058}
1059
Daniel Veillard97b58771998-10-20 06:14:16 +00001060/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001061 * xmlNewDocProp:
1062 * @doc: the document
1063 * @name: the name of the attribute
1064 * @value: the value of the attribute
1065 *
1066 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001067 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001068 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001069xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001070xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001071 xmlAttrPtr cur;
1072
1073 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001074#ifdef DEBUG_TREE
Daniel Veillardccb09631998-10-27 06:21:04 +00001075 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001076#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001077 return(NULL);
1078 }
1079
1080 /*
1081 * Allocate a new property and fill the fields.
1082 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001083 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001084 if (cur == NULL) {
1085 fprintf(stderr, "xmlNewProp : malloc failed\n");
1086 return(NULL);
1087 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001088 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001089 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001090
Daniel Veillardcf461992000-03-14 18:30:20 +00001091 cur->name = xmlStrdup(name);
1092 cur->doc = doc;
1093 if (value != NULL)
1094 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillardccb09631998-10-27 06:21:04 +00001095 return(cur);
1096}
1097
1098/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001099 * xmlFreePropList:
1100 * @cur: the first property in the list
1101 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001102 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001103 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001104void
1105xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001106 xmlAttrPtr next;
1107 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001108#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001109 fprintf(stderr, "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001110#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001111 return;
1112 }
1113 while (cur != NULL) {
1114 next = cur->next;
1115 xmlFreeProp(cur);
1116 cur = next;
1117 }
1118}
1119
Daniel Veillard97b58771998-10-20 06:14:16 +00001120/**
1121 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001122 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001123 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001124 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001125 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001126void
1127xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001128 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001129#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001130 fprintf(stderr, "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001131#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001132 return;
1133 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001134 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001135 if ((cur->parent != NULL) &&
1136 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1137 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001138 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001139 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001140 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001141 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001142}
1143
Daniel Veillard97b58771998-10-20 06:14:16 +00001144/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001145 * xmlRemoveProp:
1146 * @cur: an attribute
1147 *
1148 * Unlink and free one attribute, all the content is freed too
1149 * Note this doesn't work for namespace definition attributes
1150 *
1151 * Returns 0 if success and -1 in case of error.
1152 */
1153int
1154xmlRemoveProp(xmlAttrPtr cur) {
1155 xmlAttrPtr tmp;
1156 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001157#ifdef DEBUG_TREE
Daniel Veillard686d6b62000-01-03 11:08:02 +00001158 fprintf(stderr, "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001159#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001160 return(-1);
1161 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001162 if (cur->parent == NULL) {
1163#ifdef DEBUG_TREE
1164 fprintf(stderr, "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001165#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001166 return(-1);
1167 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001168 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001169 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001170 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001171 xmlFreeProp(cur);
1172 return(0);
1173 }
1174 while (tmp != NULL) {
1175 if (tmp->next == cur) {
1176 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001177 if (tmp->next != NULL)
1178 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001179 xmlFreeProp(cur);
1180 return(0);
1181 }
1182 tmp = tmp->next;
1183 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001184#ifdef DEBUG_TREE
Daniel Veillard686d6b62000-01-03 11:08:02 +00001185 fprintf(stderr, "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001186#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001187 return(-1);
1188}
1189
1190/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001191 * xmlNewPI:
1192 * @name: the processing instruction name
1193 * @content: the PI content
1194 *
1195 * Creation of a processing instruction element.
1196 * Returns a pointer to the new node object.
1197 */
1198xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001199xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001200 xmlNodePtr cur;
1201
1202 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001203#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001204 fprintf(stderr, "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001205#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001206 return(NULL);
1207 }
1208
1209 /*
1210 * Allocate a new node and fill the fields.
1211 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001212 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001213 if (cur == NULL) {
1214 fprintf(stderr, "xmlNewPI : malloc failed\n");
1215 return(NULL);
1216 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001217 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001218 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001219
Daniel Veillardb96e6431999-08-29 21:02:19 +00001220 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001221 if (content != NULL) {
1222#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001223 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001224#else
1225 cur->content = xmlBufferCreateSize(0);
1226 xmlBufferSetAllocationScheme(cur->content,
1227 xmlGetBufferAllocationScheme());
1228 xmlBufferAdd(cur->content, content, -1);
1229#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001230 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001231 return(cur);
1232}
1233
1234/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001235 * xmlNewNode:
1236 * @ns: namespace if any
1237 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001238 *
1239 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +00001240 * If content is non NULL, a child list containing the TEXTs and
1241 * ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001242 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001243 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001244xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001245xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001246 xmlNodePtr cur;
1247
1248 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001249#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001250 fprintf(stderr, "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001251#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001252 return(NULL);
1253 }
1254
1255 /*
1256 * Allocate a new node and fill the fields.
1257 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001258 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001259 if (cur == NULL) {
1260 fprintf(stderr, "xmlNewNode : malloc failed\n");
1261 return(NULL);
1262 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001263 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001264 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001265
Daniel Veillard260a68f1998-08-13 03:39:55 +00001266 cur->name = xmlStrdup(name);
1267 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268 return(cur);
1269}
1270
Daniel Veillard97b58771998-10-20 06:14:16 +00001271/**
1272 * xmlNewDocNode:
1273 * @doc: the document
1274 * @ns: namespace if any
1275 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001276 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001277 *
1278 * Creation of a new node element within a document. @ns and @content
1279 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001280 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1281 * references, but XML special chars need to be escaped first by using
1282 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1283 * need entities support.
1284 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001285 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001286 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001287xmlNodePtr
1288xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001289 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001290 xmlNodePtr cur;
1291
Daniel Veillardccb09631998-10-27 06:21:04 +00001292 cur = xmlNewNode(ns, name);
1293 if (cur != NULL) {
1294 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001295 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001296 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001297 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001298 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001299 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001300 return(cur);
1301}
1302
1303
Daniel Veillard97b58771998-10-20 06:14:16 +00001304/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001305 * xmlNewDocRawNode:
1306 * @doc: the document
1307 * @ns: namespace if any
1308 * @name: the node name
1309 * @content: the text content if any
1310 *
1311 * Creation of a new node element within a document. @ns and @content
1312 * are optionnal (NULL).
1313 *
1314 * Returns a pointer to the new node object.
1315 */
1316xmlNodePtr
1317xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1318 const xmlChar *name, const xmlChar *content) {
1319 xmlNodePtr cur;
1320
1321 cur = xmlNewNode(ns, name);
1322 if (cur != NULL) {
1323 cur->doc = doc;
1324 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001325 cur->children = xmlNewDocText(doc, content);
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001326 UPDATE_LAST_CHILD(cur)
1327 }
1328 }
1329 return(cur);
1330}
1331
Daniel Veillard2eac5032000-01-09 21:08:56 +00001332/**
1333 * xmlNewDocFragment:
1334 * @doc: the document owning the fragment
1335 *
1336 * Creation of a new Fragment node.
1337 * Returns a pointer to the new node object.
1338 */
1339xmlNodePtr
1340xmlNewDocFragment(xmlDocPtr doc) {
1341 xmlNodePtr cur;
1342
1343 /*
1344 * Allocate a new DocumentFragment node and fill the fields.
1345 */
1346 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1347 if (cur == NULL) {
1348 fprintf(stderr, "xmlNewDocFragment : malloc failed\n");
1349 return(NULL);
1350 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001351 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001352 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001353
Daniel Veillard2eac5032000-01-09 21:08:56 +00001354 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001355 return(cur);
1356}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001357
1358/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001359 * xmlNewText:
1360 * @content: the text content
1361 *
1362 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001363 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001364 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001365xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001366xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001367 xmlNodePtr cur;
1368
1369 /*
1370 * Allocate a new node and fill the fields.
1371 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001372 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001373 if (cur == NULL) {
1374 fprintf(stderr, "xmlNewText : malloc failed\n");
1375 return(NULL);
1376 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001377 memset(cur, 0, sizeof(xmlNode));
1378 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001379
Daniel Veillard260a68f1998-08-13 03:39:55 +00001380 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001381 if (content != NULL) {
1382#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001383 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001384#else
1385 cur->content = xmlBufferCreateSize(0);
1386 xmlBufferSetAllocationScheme(cur->content,
1387 xmlGetBufferAllocationScheme());
1388 xmlBufferAdd(cur->content, content, -1);
1389#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001390 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001391 return(cur);
1392}
1393
Daniel Veillard97b58771998-10-20 06:14:16 +00001394/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001395 * xmlNewTextChild:
1396 * @parent: the parent node
1397 * @ns: a namespace if any
1398 * @name: the name of the child
1399 * @content: the text content of the child if any.
1400 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001401 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001402 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1403 * a child TEXT node will be created containing the string content.
1404 *
1405 * Returns a pointer to the new node object.
1406 */
1407xmlNodePtr
1408xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1409 const xmlChar *name, const xmlChar *content) {
1410 xmlNodePtr cur, prev;
1411
1412 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001413#ifdef DEBUG_TREE
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001414 fprintf(stderr, "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001415#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001416 return(NULL);
1417 }
1418
1419 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001420#ifdef DEBUG_TREE
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001421 fprintf(stderr, "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001422#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001423 return(NULL);
1424 }
1425
1426 /*
1427 * Allocate a new node
1428 */
1429 if (ns == NULL)
1430 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1431 else
1432 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1433 if (cur == NULL) return(NULL);
1434
1435 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001436 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001437 */
1438 cur->type = XML_ELEMENT_NODE;
1439 cur->parent = parent;
1440 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001441 if (parent->children == NULL) {
1442 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001443 parent->last = cur;
1444 } else {
1445 prev = parent->last;
1446 prev->next = cur;
1447 cur->prev = prev;
1448 parent->last = cur;
1449 }
1450
1451 return(cur);
1452}
1453
1454/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001455 * xmlNewCharRef:
1456 * @doc: the document
1457 * @name: the char ref string, starting with # or "&# ... ;"
1458 *
1459 * Creation of a new character reference node.
1460 * Returns a pointer to the new node object.
1461 */
1462xmlNodePtr
1463xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1464 xmlNodePtr cur;
1465
1466 /*
1467 * Allocate a new node and fill the fields.
1468 */
1469 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1470 if (cur == NULL) {
1471 fprintf(stderr, "xmlNewText : malloc failed\n");
1472 return(NULL);
1473 }
1474 memset(cur, 0, sizeof(xmlNode));
1475 cur->type = XML_ENTITY_REF_NODE;
1476
1477 cur->doc = doc;
1478 if (name[0] == '&') {
1479 int len;
1480 name++;
1481 len = xmlStrlen(name);
1482 if (name[len - 1] == ';')
1483 cur->name = xmlStrndup(name, len - 1);
1484 else
1485 cur->name = xmlStrndup(name, len);
1486 } else
1487 cur->name = xmlStrdup(name);
1488 return(cur);
1489}
1490
1491/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001492 * xmlNewReference:
1493 * @doc: the document
1494 * @name: the reference name, or the reference string with & and ;
1495 *
1496 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001497 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001498 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001499xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001500xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001501 xmlNodePtr cur;
1502 xmlEntityPtr ent;
1503
1504 /*
1505 * Allocate a new node and fill the fields.
1506 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001507 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001508 if (cur == NULL) {
1509 fprintf(stderr, "xmlNewText : malloc failed\n");
1510 return(NULL);
1511 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001512 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001513 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001514
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001515 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001516 if (name[0] == '&') {
1517 int len;
1518 name++;
1519 len = xmlStrlen(name);
1520 if (name[len - 1] == ';')
1521 cur->name = xmlStrndup(name, len - 1);
1522 else
1523 cur->name = xmlStrndup(name, len);
1524 } else
1525 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001526
1527 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001528 if (ent != NULL) {
1529#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001530 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001531#else
1532 /*
1533 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1534 * a copy of this pointer. Let's hope we don't manipulate it
1535 * later
1536 */
1537 cur->content = xmlBufferCreateSize(0);
1538 xmlBufferSetAllocationScheme(cur->content,
1539 xmlGetBufferAllocationScheme());
1540 if (ent->content != NULL)
1541 xmlBufferAdd(cur->content, ent->content, -1);
1542#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001543 cur->children = (xmlNodePtr) ent;
1544 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001545 return(cur);
1546}
1547
1548/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001549 * xmlNewDocText:
1550 * @doc: the document
1551 * @content: the text content
1552 *
1553 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001554 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001555 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001556xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001557xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001558 xmlNodePtr cur;
1559
1560 cur = xmlNewText(content);
1561 if (cur != NULL) cur->doc = doc;
1562 return(cur);
1563}
1564
Daniel Veillard97b58771998-10-20 06:14:16 +00001565/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001566 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001567 * @content: the text content
1568 * @len: the text len.
1569 *
1570 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001571 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001572 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001573xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001574xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001575 xmlNodePtr cur;
1576
1577 /*
1578 * Allocate a new node and fill the fields.
1579 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001580 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001581 if (cur == NULL) {
1582 fprintf(stderr, "xmlNewText : malloc failed\n");
1583 return(NULL);
1584 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001585 memset(cur, 0, sizeof(xmlNode));
1586 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001587
Daniel Veillard260a68f1998-08-13 03:39:55 +00001588 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001589 if (content != NULL) {
1590#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001591 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001592#else
1593 cur->content = xmlBufferCreateSize(len);
1594 xmlBufferSetAllocationScheme(cur->content,
1595 xmlGetBufferAllocationScheme());
1596 xmlBufferAdd(cur->content, content, len);
1597#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001598 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001599 return(cur);
1600}
1601
Daniel Veillard97b58771998-10-20 06:14:16 +00001602/**
1603 * xmlNewDocTextLen:
1604 * @doc: the document
1605 * @content: the text content
1606 * @len: the text len.
1607 *
1608 * Creation of a new text node with an extra content lenght parameter. The
1609 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001610 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001611 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001612xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001613xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001614 xmlNodePtr cur;
1615
1616 cur = xmlNewTextLen(content, len);
1617 if (cur != NULL) cur->doc = doc;
1618 return(cur);
1619}
1620
Daniel Veillard97b58771998-10-20 06:14:16 +00001621/**
1622 * xmlNewComment:
1623 * @content: the comment content
1624 *
1625 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001626 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001627 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001628xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001629xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001630 xmlNodePtr cur;
1631
1632 /*
1633 * Allocate a new node and fill the fields.
1634 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001635 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001636 if (cur == NULL) {
1637 fprintf(stderr, "xmlNewComment : malloc failed\n");
1638 return(NULL);
1639 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001640 memset(cur, 0, sizeof(xmlNode));
1641 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001642
Daniel Veillardcf461992000-03-14 18:30:20 +00001643 cur->name = xmlStrdup(xmlStringComment);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001644 if (content != NULL) {
1645#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001646 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001647#else
1648 cur->content = xmlBufferCreateSize(0);
1649 xmlBufferSetAllocationScheme(cur->content,
1650 xmlGetBufferAllocationScheme());
1651 xmlBufferAdd(cur->content, content, -1);
1652#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001653 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001654 return(cur);
1655}
1656
Daniel Veillard97b58771998-10-20 06:14:16 +00001657/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001658 * xmlNewCDataBlock:
1659 * @doc: the document
1660 * @content: the CData block content content
1661 * @len: the length of the block
1662 *
1663 * Creation of a new node containing a CData block.
1664 * Returns a pointer to the new node object.
1665 */
1666xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001667xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001668 xmlNodePtr cur;
1669
1670 /*
1671 * Allocate a new node and fill the fields.
1672 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001673 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001674 if (cur == NULL) {
1675 fprintf(stderr, "xmlNewCDataBlock : malloc failed\n");
1676 return(NULL);
1677 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001678 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001679 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001680
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001681 if (content != NULL) {
1682#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001683 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001684#else
1685 cur->content = xmlBufferCreateSize(len);
1686 xmlBufferSetAllocationScheme(cur->content,
1687 xmlGetBufferAllocationScheme());
1688 xmlBufferAdd(cur->content, content, len);
1689#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001690 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001691 return(cur);
1692}
1693
1694/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001695 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001696 * @doc: the document
1697 * @content: the comment content
1698 *
1699 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001700 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001701 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001702xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001703xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001704 xmlNodePtr cur;
1705
1706 cur = xmlNewComment(content);
1707 if (cur != NULL) cur->doc = doc;
1708 return(cur);
1709}
1710
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001711
Daniel Veillard97b58771998-10-20 06:14:16 +00001712/**
1713 * xmlNewChild:
1714 * @parent: the parent node
1715 * @ns: a namespace if any
1716 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001717 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001718 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001719 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001720 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1721 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001722 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1723 * references, but XML special chars need to be escaped first by using
1724 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1725 * support is not needed.
1726 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001727 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001728 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001729xmlNodePtr
1730xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001731 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001732 xmlNodePtr cur, prev;
1733
1734 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001735#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001736 fprintf(stderr, "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001737#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001738 return(NULL);
1739 }
1740
1741 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001742#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001743 fprintf(stderr, "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001744#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001745 return(NULL);
1746 }
1747
1748 /*
1749 * Allocate a new node
1750 */
1751 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001752 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001753 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001754 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001755 if (cur == NULL) return(NULL);
1756
1757 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001758 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001759 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001760 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001761 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001762 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001763 if (parent->children == NULL) {
1764 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001765 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001766 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001767 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001768 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001769 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001770 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001771 }
1772
1773 return(cur);
1774}
1775
Daniel Veillard97b58771998-10-20 06:14:16 +00001776/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001777 * xmlAddNextSibling:
1778 * @cur: the child node
1779 * @elem: the new node
1780 *
1781 * Add a new element @elem as the next siblings of @cur
1782 * If the new element was already inserted in a document it is
1783 * first unlinked from its existing context.
1784 *
1785 * Returns the new element or NULL in case of error.
1786 */
1787xmlNodePtr
1788xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1789 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001790#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001791 fprintf(stderr, "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001792#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001793 return(NULL);
1794 }
1795 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001796#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001797 fprintf(stderr, "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001798#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001799 return(NULL);
1800 }
1801
1802 xmlUnlinkNode(elem);
1803 elem->doc = cur->doc;
1804 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001805 elem->prev = cur;
1806 elem->next = cur->next;
1807 cur->next = elem;
1808 if (elem->next != NULL)
1809 elem->next->prev = elem;
1810 if ((elem->parent != NULL) && (elem->parent->last == cur))
1811 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001812 return(elem);
1813}
1814
1815/**
1816 * xmlAddPrevSibling:
1817 * @cur: the child node
1818 * @elem: the new node
1819 *
1820 * Add a new element @elem as the previous siblings of @cur
1821 * If the new element was already inserted in a document it is
1822 * first unlinked from its existing context.
1823 *
1824 * Returns the new element or NULL in case of error.
1825 */
1826xmlNodePtr
1827xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1828 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001829#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001830 fprintf(stderr, "xmlAddPrevSibling : 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 Veillard5cb5ab81999-12-21 15:35:29 +00001836 fprintf(stderr, "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001837#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001838 return(NULL);
1839 }
1840
1841 xmlUnlinkNode(elem);
1842 elem->doc = cur->doc;
1843 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001844 elem->next = cur;
1845 elem->prev = cur->prev;
1846 cur->prev = elem;
1847 if (elem->prev != NULL)
1848 elem->prev->next = elem;
1849 if ((elem->parent != NULL) && (elem->parent->children == cur))
1850 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001851 return(elem);
1852}
1853
1854/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001855 * xmlAddSibling:
1856 * @cur: the child node
1857 * @elem: the new node
1858 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001859 * Add a new element @elem to the list of siblings of @cur
1860 * If the new element was already inserted in a document it is
1861 * first unlinked from its existing context.
1862 *
1863 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001864 */
1865xmlNodePtr
1866xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1867 xmlNodePtr parent;
1868
1869 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001870#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001871 fprintf(stderr, "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001872#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001873 return(NULL);
1874 }
1875
1876 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001877#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001878 fprintf(stderr, "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001879#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001880 return(NULL);
1881 }
1882
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001883 /*
1884 * Constant time is we can rely on the ->parent->last to find
1885 * the last sibling.
1886 */
1887 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001888 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001889 (cur->parent->last != NULL) &&
1890 (cur->parent->last->next == NULL)) {
1891 cur = cur->parent->last;
1892 } else {
1893 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001894 }
1895
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001896 xmlUnlinkNode(elem);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001897 if (elem->doc == NULL)
1898 elem->doc = cur->doc; /* the parent may not be linked to a doc ! */
1899
1900 parent = cur->parent;
1901 elem->prev = cur;
1902 elem->next = NULL;
1903 elem->parent = parent;
1904 cur->next = elem;
1905 if (parent != NULL)
1906 parent->last = elem;
1907
1908 return(elem);
1909}
1910
1911/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001912 * xmlAddChild:
1913 * @parent: the parent node
1914 * @cur: the child node
1915 *
1916 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001917 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001918 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001919xmlNodePtr
1920xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001921 xmlNodePtr prev;
1922
1923 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001924#ifdef DEBUG_TREE
Daniel Veillard10a2c651999-12-12 13:03:50 +00001925 fprintf(stderr, "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001926#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001927 return(NULL);
1928 }
1929
1930 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001931#ifdef DEBUG_TREE
Daniel Veillard10a2c651999-12-12 13:03:50 +00001932 fprintf(stderr, "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001933#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001934 return(NULL);
1935 }
1936
Daniel Veillard0bef1311998-10-14 02:36:47 +00001937 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1938 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001939#ifdef DEBUG_TREE
Daniel Veillard0bef1311998-10-14 02:36:47 +00001940 fprintf(stderr, "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001941#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00001942 }
1943
Daniel Veillard260a68f1998-08-13 03:39:55 +00001944 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001945 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001946 */
1947 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001948 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001949
Daniel Veillardccb09631998-10-27 06:21:04 +00001950 /*
1951 * Handle the case where parent->content != NULL, in that case it will
1952 * create a intermediate TEXT node.
1953 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001954 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
1955 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001956 xmlNodePtr text;
1957
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001958#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001959 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001960#else
1961 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
1962#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001963 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001964 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00001965 if (text->next != NULL)
1966 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00001967 parent->children = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001968 UPDATE_LAST_CHILD(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001969#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00001970 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001971#else
1972 xmlBufferFree(parent->content);
1973#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001974 parent->content = NULL;
1975 }
1976 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001977 if (parent->children == NULL) {
1978 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001979 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001980 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001981 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001982 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001983 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001984 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001985 }
1986
1987 return(cur);
1988}
1989
Daniel Veillard97b58771998-10-20 06:14:16 +00001990/**
1991 * xmlGetLastChild:
1992 * @parent: the parent node
1993 *
1994 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001995 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001996 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001997xmlNodePtr
1998xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001999 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002000#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002001 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002002#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002003 return(NULL);
2004 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002005 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002006}
2007
Daniel Veillard97b58771998-10-20 06:14:16 +00002008/**
2009 * xmlFreeNodeList:
2010 * @cur: the first node in the list
2011 *
2012 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002013 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002014 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002015void
2016xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002017 xmlNodePtr next;
2018 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002019#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002020 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002021#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002022 return;
2023 }
2024 while (cur != NULL) {
2025 next = cur->next;
2026 xmlFreeNode(cur);
2027 cur = next;
2028 }
2029}
2030
Daniel Veillard97b58771998-10-20 06:14:16 +00002031/**
2032 * xmlFreeNode:
2033 * @cur: the node
2034 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002035 * Free a node, this is a recursive behaviour, all the children are freed too.
2036 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002037 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002038void
2039xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002040 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002041#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002042 fprintf(stderr, "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002043#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002044 return;
2045 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002046 if (cur->type == XML_DTD_NODE)
2047 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002048 cur->doc = NULL;
2049 cur->parent = NULL;
2050 cur->next = NULL;
2051 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002052 if ((cur->children != NULL) &&
2053 (cur->type != XML_ENTITY_REF_NODE))
2054 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002055 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2056 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002057#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002058 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002059#else
2060 if (cur->content != NULL) xmlBufferFree(cur->content);
2061#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00002062 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002063 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2064 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002065 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002066}
2067
Daniel Veillard16253641998-10-28 22:58:05 +00002068/**
2069 * xmlUnlinkNode:
2070 * @cur: the node
2071 *
2072 * Unlink a node from it's current context, the node is not freed
2073 */
2074void
2075xmlUnlinkNode(xmlNodePtr cur) {
2076 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002077#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00002078 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002079#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002080 return;
2081 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002082 if ((cur->parent != NULL) && (cur->parent->children == cur))
2083 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002084 if ((cur->parent != NULL) && (cur->parent->last == cur))
2085 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002086 if (cur->next != NULL)
2087 cur->next->prev = cur->prev;
2088 if (cur->prev != NULL)
2089 cur->prev->next = cur->next;
2090 cur->next = cur->prev = NULL;
2091 cur->parent = NULL;
2092}
2093
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002094/**
2095 * xmlReplaceNode:
2096 * @old: the old node
2097 * @cur: the node
2098 *
2099 * Unlink the old node from it's current context, prune the new one
2100 * at the same place. If cur was already inserted in a document it is
2101 * first unlinked from its existing context.
2102 *
2103 * Returns the old node
2104 */
2105xmlNodePtr
2106xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2107 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002108#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002109 fprintf(stderr, "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002110#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002111 return(NULL);
2112 }
2113 if (cur == NULL) {
2114 xmlUnlinkNode(old);
2115 return(old);
2116 }
2117 xmlUnlinkNode(cur);
2118 cur->doc = old->doc;
2119 cur->parent = old->parent;
2120 cur->next = old->next;
2121 if (cur->next != NULL)
2122 cur->next->prev = cur;
2123 cur->prev = old->prev;
2124 if (cur->prev != NULL)
2125 cur->prev->next = cur;
2126 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002127 if (cur->parent->children == old)
2128 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002129 if (cur->parent->last == old)
2130 cur->parent->last = cur;
2131 }
2132 old->next = old->prev = NULL;
2133 old->parent = NULL;
2134 return(old);
2135}
2136
Daniel Veillard260a68f1998-08-13 03:39:55 +00002137/************************************************************************
2138 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002139 * Copy operations *
2140 * *
2141 ************************************************************************/
2142
2143/**
2144 * xmlCopyNamespace:
2145 * @cur: the namespace
2146 *
2147 * Do a copy of the namespace.
2148 *
2149 * Returns: a new xmlNsPtr, or NULL in case of error.
2150 */
2151xmlNsPtr
2152xmlCopyNamespace(xmlNsPtr cur) {
2153 xmlNsPtr ret;
2154
2155 if (cur == NULL) return(NULL);
2156 switch (cur->type) {
2157 case XML_GLOBAL_NAMESPACE:
2158 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
2159 break;
2160 case XML_LOCAL_NAMESPACE:
2161 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2162 break;
2163 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002164#ifdef DEBUG_TREE
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002165 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002166#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002167 return(NULL);
2168 }
2169 return(ret);
2170}
2171
2172/**
2173 * xmlCopyNamespaceList:
2174 * @cur: the first namespace
2175 *
2176 * Do a copy of an namespace list.
2177 *
2178 * Returns: a new xmlNsPtr, or NULL in case of error.
2179 */
2180xmlNsPtr
2181xmlCopyNamespaceList(xmlNsPtr cur) {
2182 xmlNsPtr ret = NULL;
2183 xmlNsPtr p = NULL,q;
2184
2185 while (cur != NULL) {
2186 q = xmlCopyNamespace(cur);
2187 if (p == NULL) {
2188 ret = p = q;
2189 } else {
2190 p->next = q;
2191 p = q;
2192 }
2193 cur = cur->next;
2194 }
2195 return(ret);
2196}
2197
2198/**
2199 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002200 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002201 * @cur: the attribute
2202 *
2203 * Do a copy of the attribute.
2204 *
2205 * Returns: a new xmlAttrPtr, or NULL in case of error.
2206 */
2207xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002208xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002209 xmlAttrPtr ret;
2210
2211 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002212 if (cur->parent != NULL)
2213 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2214 else if (cur->children != NULL)
2215 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002216 else
2217 ret = xmlNewDocProp(NULL, cur->name, NULL);
2218 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002219 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002220
2221 if ((cur->ns != NULL) && (target != NULL)) {
2222 xmlNsPtr ns;
2223
2224 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2225 ret->ns = ns;
2226 } else
2227 ret->ns = NULL;
2228
Daniel Veillardcf461992000-03-14 18:30:20 +00002229 if (cur->children != NULL)
2230 ret->children = xmlCopyNodeList(cur->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002231 return(ret);
2232}
2233
2234/**
2235 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002236 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002237 * @cur: the first attribute
2238 *
2239 * Do a copy of an attribute list.
2240 *
2241 * Returns: a new xmlAttrPtr, or NULL in case of error.
2242 */
2243xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002244xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002245 xmlAttrPtr ret = NULL;
2246 xmlAttrPtr p = NULL,q;
2247
2248 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002249 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002250 if (p == NULL) {
2251 ret = p = q;
2252 } else {
2253 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002254 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002255 p = q;
2256 }
2257 cur = cur->next;
2258 }
2259 return(ret);
2260}
2261
2262/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002263 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002264 *
2265 * They are splitted into external and internal parts for one
2266 * tricky reason: namespaces. Doing a direct copy of a node
2267 * say RPM:Copyright without changing the namespace pointer to
2268 * something else can produce stale links. One way to do it is
2269 * to keep a reference counter but this doesn't work as soon
2270 * as one move the element or the subtree out of the scope of
2271 * the existing namespace. The actual solution seems to add
2272 * a copy of the namespace at the top of the copied tree if
2273 * not available in the subtree.
2274 * Hence two functions, the public front-end call the inner ones
2275 */
2276
2277static xmlNodePtr
2278xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2279
2280static xmlNodePtr
2281xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2282 int recursive) {
2283 xmlNodePtr ret;
2284
2285 if (node == NULL) return(NULL);
2286 /*
2287 * Allocate a new node and fill the fields.
2288 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002289 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002290 if (ret == NULL) {
2291 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
2292 return(NULL);
2293 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002294 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002295 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002296
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002297 ret->doc = doc;
2298 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002299 if (node->name != NULL)
2300 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002301 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2302#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002303 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002304#else
2305 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2306 xmlBufferSetAllocationScheme(ret->content,
2307 xmlGetBufferAllocationScheme());
2308 xmlBufferAdd(ret->content,
2309 xmlBufferContent(node->content),
2310 xmlBufferLength(node->content));
2311#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002312 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002313 if (parent != NULL)
2314 xmlAddChild(parent, ret);
2315
2316 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002317 if (node->nsDef != NULL)
2318 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2319
2320 if (node->ns != NULL) {
2321 xmlNsPtr ns;
2322
2323 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2324 if (ns == NULL) {
2325 /*
2326 * Humm, we are copying an element whose namespace is defined
2327 * out of the new tree scope. Search it in the original tree
2328 * and add it at the top of the new tree
2329 */
2330 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2331 if (ns != NULL) {
2332 xmlNodePtr root = ret;
2333
2334 while (root->parent != NULL) root = root->parent;
2335 xmlNewNs(root, ns->href, ns->prefix);
2336 }
2337 } else {
2338 /*
2339 * reference the existing namespace definition in our own tree.
2340 */
2341 ret->ns = ns;
2342 }
2343 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002344 if (node->properties != NULL)
2345 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002346 if (node->children != NULL)
2347 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002348 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002349 return(ret);
2350}
2351
2352static xmlNodePtr
2353xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2354 xmlNodePtr ret = NULL;
2355 xmlNodePtr p = NULL,q;
2356
2357 while (node != NULL) {
2358 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002359 if (ret == NULL) {
2360 q->prev = NULL;
2361 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002362 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002363 p->next = q;
2364 q->prev = p;
2365 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002366 }
2367 node = node->next;
2368 }
2369 return(ret);
2370}
2371
2372/**
2373 * xmlCopyNode:
2374 * @node: the node
2375 * @recursive: if 1 do a recursive copy.
2376 *
2377 * Do a copy of the node.
2378 *
2379 * Returns: a new xmlNodePtr, or NULL in case of error.
2380 */
2381xmlNodePtr
2382xmlCopyNode(xmlNodePtr node, int recursive) {
2383 xmlNodePtr ret;
2384
2385 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2386 return(ret);
2387}
2388
2389/**
2390 * xmlCopyNodeList:
2391 * @node: the first node in the list.
2392 *
2393 * Do a recursive copy of the node list.
2394 *
2395 * Returns: a new xmlNodePtr, or NULL in case of error.
2396 */
2397xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2398 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2399 return(ret);
2400}
2401
2402/**
2403 * xmlCopyElement:
2404 * @elem: the element
2405 *
2406 * Do a copy of the element definition.
2407 *
2408 * Returns: a new xmlElementPtr, or NULL in case of error.
2409xmlElementPtr
2410xmlCopyElement(xmlElementPtr elem) {
2411 xmlElementPtr ret;
2412
2413 if (elem == NULL) return(NULL);
2414 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2415 if (ret == NULL) return(NULL);
2416 if (!recursive) return(ret);
2417 if (elem->properties != NULL)
2418 ret->properties = xmlCopyPropList(elem->properties);
2419
2420 if (elem->nsDef != NULL)
2421 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002422 if (elem->children != NULL)
2423 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002424 return(ret);
2425}
2426 */
2427
2428/**
2429 * xmlCopyDtd:
2430 * @dtd: the dtd
2431 *
2432 * Do a copy of the dtd.
2433 *
2434 * Returns: a new xmlDtdPtr, or NULL in case of error.
2435 */
2436xmlDtdPtr
2437xmlCopyDtd(xmlDtdPtr dtd) {
2438 xmlDtdPtr ret;
2439
2440 if (dtd == NULL) return(NULL);
2441 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2442 if (ret == NULL) return(NULL);
2443 if (dtd->entities != NULL)
2444 ret->entities = (void *) xmlCopyEntitiesTable(
2445 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002446 if (dtd->notations != NULL)
2447 ret->notations = (void *) xmlCopyNotationTable(
2448 (xmlNotationTablePtr) dtd->notations);
2449 if (dtd->elements != NULL)
2450 ret->elements = (void *) xmlCopyElementTable(
2451 (xmlElementTablePtr) dtd->elements);
2452 if (dtd->attributes != NULL)
2453 ret->attributes = (void *) xmlCopyAttributeTable(
2454 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002455 return(ret);
2456}
2457
2458/**
2459 * xmlCopyDoc:
2460 * @doc: the document
2461 * @recursive: if 1 do a recursive copy.
2462 *
2463 * Do a copy of the document info. If recursive, the content tree will
2464 * be copied too as well as Dtd, namespaces and entities.
2465 *
2466 * Returns: a new xmlDocPtr, or NULL in case of error.
2467 */
2468xmlDocPtr
2469xmlCopyDoc(xmlDocPtr doc, int recursive) {
2470 xmlDocPtr ret;
2471
2472 if (doc == NULL) return(NULL);
2473 ret = xmlNewDoc(doc->version);
2474 if (ret == NULL) return(NULL);
2475 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002476 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002477 if (doc->encoding != NULL)
2478 ret->encoding = xmlStrdup(doc->encoding);
2479 ret->compression = doc->compression;
2480 ret->standalone = doc->standalone;
2481 if (!recursive) return(ret);
2482
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002483 if (doc->intSubset != NULL)
2484 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002485 if (doc->oldNs != NULL)
2486 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillardcf461992000-03-14 18:30:20 +00002487 if (doc->children != NULL)
Daniel Veillard06047432000-04-24 11:33:38 +00002488 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2489 (xmlNodePtr)ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002490 return(ret);
2491}
2492
2493/************************************************************************
2494 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002495 * Content access functions *
2496 * *
2497 ************************************************************************/
2498
Daniel Veillard97b58771998-10-20 06:14:16 +00002499/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002500 * xmlDocGetRootElement:
2501 * @doc: the document
2502 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002503 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002504 * containing possibly comments, PIs, etc ...).
2505 *
2506 * Returns the xmlNodePtr for the root or NULL
2507 */
2508xmlNodePtr
2509xmlDocGetRootElement(xmlDocPtr doc) {
2510 xmlNodePtr ret;
2511
2512 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002513 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002514 while (ret != NULL) {
2515 if (ret->type == XML_ELEMENT_NODE)
2516 return(ret);
2517 ret = ret->next;
2518 }
2519 return(ret);
2520}
2521
2522/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002523 * xmlDocSetRootElement:
2524 * @doc: the document
2525 * @root: the new document root element
2526 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002527 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002528 * containing possibly comments, PIs, etc ...).
2529 *
2530 * Returns the old root element if any was found
2531 */
2532xmlNodePtr
2533xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2534 xmlNodePtr old = NULL;
2535
2536 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002537 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002538 while (old != NULL) {
2539 if (old->type == XML_ELEMENT_NODE)
2540 break;
2541 old = old->next;
2542 }
2543 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002544 if (doc->children == NULL) {
2545 doc->children = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002546 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002547 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002548 }
2549 } else {
2550 xmlReplaceNode(old, root);
2551 }
2552 return(old);
2553}
2554
2555/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002556 * xmlNodeSetLang:
2557 * @cur: the node being changed
2558 * @lang: the langage description
2559 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002560 * Set the language of a node, i.e. the values of the xml:lang
2561 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002562 */
2563void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002564xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002565 if (cur == NULL) return;
2566 switch(cur->type) {
2567 case XML_TEXT_NODE:
2568 case XML_CDATA_SECTION_NODE:
2569 case XML_COMMENT_NODE:
2570 case XML_DOCUMENT_NODE:
2571 case XML_DOCUMENT_TYPE_NODE:
2572 case XML_DOCUMENT_FRAG_NODE:
2573 case XML_NOTATION_NODE:
2574 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002575 case XML_DTD_NODE:
2576 case XML_ELEMENT_DECL:
2577 case XML_ATTRIBUTE_DECL:
2578 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002579 return;
2580 case XML_ELEMENT_NODE:
2581 case XML_ATTRIBUTE_NODE:
2582 case XML_PI_NODE:
2583 case XML_ENTITY_REF_NODE:
2584 case XML_ENTITY_NODE:
2585 break;
2586 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002587 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2588}
2589
2590/**
2591 * xmlNodeGetLang:
2592 * @cur: the node being checked
2593 *
2594 * Searches the language of a node, i.e. the values of the xml:lang
2595 * attribute or the one carried by the nearest ancestor.
2596 *
2597 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002598 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002599 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002600xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002601xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002602 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002603
2604 while (cur != NULL) {
2605 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2606 if (lang != NULL)
2607 return(lang);
2608 cur = cur->parent;
2609 }
2610 return(NULL);
2611}
2612
2613/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002614 * xmlNodeGetSpacePreserve:
2615 * @cur: the node being checked
2616 *
2617 * Searches the language of a node, i.e. the values of the xml:space
2618 * attribute or the one carried by the nearest ancestor.
2619 *
2620 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2621 */
2622int
2623xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2624 xmlChar *space;
2625
2626 while (cur != NULL) {
2627 space = xmlGetProp(cur, BAD_CAST "xml:space");
2628 if (space != NULL) {
2629 if (!xmlStrcmp(space, BAD_CAST "preserve")) {
2630 xmlFree(space);
2631 return(1);
2632 }
2633 if (!xmlStrcmp(space, BAD_CAST "default")) {
2634 xmlFree(space);
2635 return(0);
2636 }
2637 xmlFree(space);
2638 }
2639 cur = cur->parent;
2640 }
2641 return(-1);
2642}
2643
2644/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002645 * xmlNodeSetName:
2646 * @cur: the node being changed
2647 * @name: the new tag name
2648 *
2649 * Searches the language of a node, i.e. the values of the xml:lang
2650 * attribute or the one carried by the nearest ancestor.
2651 */
2652void
2653xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2654 if (cur == NULL) return;
2655 if (name == NULL) return;
2656 switch(cur->type) {
2657 case XML_TEXT_NODE:
2658 case XML_CDATA_SECTION_NODE:
2659 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002660 case XML_DOCUMENT_TYPE_NODE:
2661 case XML_DOCUMENT_FRAG_NODE:
2662 case XML_NOTATION_NODE:
2663 case XML_HTML_DOCUMENT_NODE:
2664 return;
2665 case XML_ELEMENT_NODE:
2666 case XML_ATTRIBUTE_NODE:
2667 case XML_PI_NODE:
2668 case XML_ENTITY_REF_NODE:
2669 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002670 case XML_DTD_NODE:
2671 case XML_DOCUMENT_NODE:
2672 case XML_ELEMENT_DECL:
2673 case XML_ATTRIBUTE_DECL:
2674 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002675 break;
2676 }
2677 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
2678 cur->name = xmlStrdup(name);
2679}
2680
2681/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00002682 * xmlNodeGetBase:
2683 * @doc: the document the node pertains to
2684 * @cur: the node being checked
2685 *
2686 * Searches for the BASE URL. The code should work on both XML
2687 * and HTML document even if base mechanisms are completely different.
2688 *
2689 * Returns a pointer to the base URL, or NULL if not found
2690 * It's up to the caller to free the memory.
2691 */
2692xmlChar *
2693xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
2694 xmlChar *base;
2695
2696 if ((cur == NULL) && (doc == NULL))
2697 return(NULL);
2698 if (doc == NULL) doc = cur->doc;
2699 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002700 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002701 while ((cur != NULL) && (cur->name != NULL)) {
2702 if (cur->type != XML_ELEMENT_NODE) {
2703 cur = cur->next;
2704 continue;
2705 }
2706 if ((!xmlStrcmp(cur->name, BAD_CAST "html")) ||
2707 (!xmlStrcmp(cur->name, BAD_CAST "HTML"))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002708 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002709 continue;
2710 }
2711 if ((!xmlStrcmp(cur->name, BAD_CAST "head")) ||
2712 (!xmlStrcmp(cur->name, BAD_CAST "HEAD"))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002713 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002714 continue;
2715 }
2716 if ((!xmlStrcmp(cur->name, BAD_CAST "base")) ||
2717 (!xmlStrcmp(cur->name, BAD_CAST "BASE"))) {
2718 base = xmlGetProp(cur, BAD_CAST "href");
2719 if (base != NULL) return(base);
2720 return(xmlGetProp(cur, BAD_CAST "HREF"));
2721 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002722 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002723 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002724 if ((doc != NULL) && (doc->URL != NULL))
2725 return(xmlStrdup(doc->URL));
Daniel Veillard10a2c651999-12-12 13:03:50 +00002726 return(NULL);
2727 }
2728 while (cur != NULL) {
2729 base = xmlGetProp(cur, BAD_CAST "xml:base");
2730 if (base != NULL)
2731 return(base);
2732 cur = cur->parent;
2733 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002734 if ((doc != NULL) && (doc->URL != NULL))
2735 return(xmlStrdup(doc->URL));
Daniel Veillard10a2c651999-12-12 13:03:50 +00002736 return(NULL);
2737}
2738
2739/**
Daniel Veillard16253641998-10-28 22:58:05 +00002740 * xmlNodeGetContent:
2741 * @cur: the node being read
2742 *
2743 * Read the value of a node, this can be either the text carried
2744 * directly by this node if it's a TEXT node or the aggregate string
2745 * of the values carried by this node child's (TEXT and ENTITY_REF).
2746 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002747 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00002748 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00002749 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002750xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00002751xmlNodeGetContent(xmlNodePtr cur) {
2752 if (cur == NULL) return(NULL);
2753 switch (cur->type) {
2754 case XML_DOCUMENT_FRAG_NODE:
2755 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002756 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00002757 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002758 case XML_ATTRIBUTE_NODE: {
2759 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00002760 if (attr->parent != NULL)
2761 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002762 else
Daniel Veillardcf461992000-03-14 18:30:20 +00002763 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002764 break;
2765 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002766 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002767 case XML_PI_NODE:
2768 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002769#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00002770 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002771#else
2772 return(xmlStrdup(xmlBufferContent(cur->content)));
2773#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002774 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00002775 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002776 /*
2777 * Locate the entity, and get it's content
2778 * @@@
2779 */
2780 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00002781 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002782 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002783 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002784 case XML_DOCUMENT_TYPE_NODE:
2785 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002786 case XML_DTD_NODE:
2787 return(NULL);
2788 case XML_ELEMENT_DECL:
2789 /* TODO !!! */
2790 return(NULL);
2791 case XML_ATTRIBUTE_DECL:
2792 /* TODO !!! */
2793 return(NULL);
2794 case XML_ENTITY_DECL:
2795 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00002796 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002797 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002798 case XML_TEXT_NODE:
2799 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002800#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00002801 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002802#else
2803 return(xmlStrdup(xmlBufferContent(cur->content)));
2804#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002805 return(NULL);
2806 }
2807 return(NULL);
2808}
2809
2810/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002811 * xmlNodeSetContent:
2812 * @cur: the node being modified
2813 * @content: the new value of the content
2814 *
2815 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002816 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002817void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002818xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002819 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002820#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002821 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002822#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002823 return;
2824 }
Daniel Veillard16253641998-10-28 22:58:05 +00002825 switch (cur->type) {
2826 case XML_DOCUMENT_FRAG_NODE:
2827 case XML_ELEMENT_NODE:
2828 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002829#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002830 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002831#else
2832 xmlBufferFree(cur->content);
2833#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002834 cur->content = NULL;
2835 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002836 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2837 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002838 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00002839 break;
2840 case XML_ATTRIBUTE_NODE:
2841 break;
2842 case XML_TEXT_NODE:
2843 case XML_CDATA_SECTION_NODE:
2844 case XML_ENTITY_REF_NODE:
2845 case XML_ENTITY_NODE:
2846 case XML_PI_NODE:
2847 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002848 if (cur->content != NULL) {
2849#ifndef XML_USE_BUFFER_CONTENT
2850 xmlFree(cur->content);
2851#else
2852 xmlBufferFree(cur->content);
2853#endif
2854 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002855 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2856 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002857 if (content != NULL) {
2858#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00002859 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002860#else
2861 cur->content = xmlBufferCreateSize(0);
2862 xmlBufferSetAllocationScheme(cur->content,
2863 xmlGetBufferAllocationScheme());
2864 xmlBufferAdd(cur->content, content, -1);
2865#endif
2866 } else
Daniel Veillard16253641998-10-28 22:58:05 +00002867 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002868 break;
Daniel Veillard16253641998-10-28 22:58:05 +00002869 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002870 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002871 case XML_DOCUMENT_TYPE_NODE:
2872 break;
2873 case XML_NOTATION_NODE:
2874 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00002875 case XML_DTD_NODE:
2876 break;
2877 case XML_ELEMENT_DECL:
2878 /* TODO !!! */
2879 break;
2880 case XML_ATTRIBUTE_DECL:
2881 /* TODO !!! */
2882 break;
2883 case XML_ENTITY_DECL:
2884 /* TODO !!! */
2885 break;
Daniel Veillard16253641998-10-28 22:58:05 +00002886 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002887}
2888
Daniel Veillard97b58771998-10-20 06:14:16 +00002889/**
2890 * xmlNodeSetContentLen:
2891 * @cur: the node being modified
2892 * @content: the new value of the content
2893 * @len: the size of @content
2894 *
2895 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002896 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002897void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002898xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002899 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002900#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00002901 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002902#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002903 return;
2904 }
Daniel Veillard16253641998-10-28 22:58:05 +00002905 switch (cur->type) {
2906 case XML_DOCUMENT_FRAG_NODE:
2907 case XML_ELEMENT_NODE:
2908 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002909#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002910 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002911#else
2912 xmlBufferFree(cur->content);
2913#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002914 cur->content = NULL;
2915 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002916 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2917 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002918 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00002919 break;
2920 case XML_ATTRIBUTE_NODE:
2921 break;
2922 case XML_TEXT_NODE:
2923 case XML_CDATA_SECTION_NODE:
2924 case XML_ENTITY_REF_NODE:
2925 case XML_ENTITY_NODE:
2926 case XML_PI_NODE:
2927 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002928 case XML_NOTATION_NODE:
2929 if (cur->content != NULL) {
2930#ifndef XML_USE_BUFFER_CONTENT
2931 xmlFree(cur->content);
2932#else
2933 xmlBufferFree(cur->content);
2934#endif
2935 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002936 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2937 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002938 if (content != NULL) {
2939#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00002940 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002941#else
2942 cur->content = xmlBufferCreateSize(len);
2943 xmlBufferSetAllocationScheme(cur->content,
2944 xmlGetBufferAllocationScheme());
2945 xmlBufferAdd(cur->content, content, len);
2946#endif
2947 } else
Daniel Veillard16253641998-10-28 22:58:05 +00002948 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002949 break;
Daniel Veillard16253641998-10-28 22:58:05 +00002950 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002951 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002952 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002953 case XML_DOCUMENT_TYPE_NODE:
2954 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00002955 case XML_ELEMENT_DECL:
2956 /* TODO !!! */
2957 break;
2958 case XML_ATTRIBUTE_DECL:
2959 /* TODO !!! */
2960 break;
2961 case XML_ENTITY_DECL:
2962 /* TODO !!! */
2963 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002964 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002965}
2966
Daniel Veillard97b58771998-10-20 06:14:16 +00002967/**
2968 * xmlNodeAddContentLen:
2969 * @cur: the node being modified
2970 * @content: extra content
2971 * @len: the size of @content
2972 *
2973 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002974 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002975void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002976xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002977 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002978#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00002979 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002980#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002981 return;
2982 }
2983 if (len <= 0) return;
2984 switch (cur->type) {
2985 case XML_DOCUMENT_FRAG_NODE:
2986 case XML_ELEMENT_NODE: {
2987 xmlNodePtr last = NULL, new;
2988
Daniel Veillardcf461992000-03-14 18:30:20 +00002989 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002990 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00002991 } else {
2992 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002993#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00002994 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002995#else
Daniel Veillardcf461992000-03-14 18:30:20 +00002996 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002997 xmlBufferContent(cur->content));
2998#endif
Daniel Veillard1e346af1999-02-22 10:33:01 +00002999 UPDATE_LAST_CHILD(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003000#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003001 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003002#else
3003 xmlBufferFree(cur->content);
3004#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003005 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003006 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003007 }
3008 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003009 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00003010 if (new != NULL) {
3011 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003012 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00003013 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003014 }
Daniel Veillard16253641998-10-28 22:58:05 +00003015 }
3016 break;
3017 }
3018 case XML_ATTRIBUTE_NODE:
3019 break;
3020 case XML_TEXT_NODE:
3021 case XML_CDATA_SECTION_NODE:
3022 case XML_ENTITY_REF_NODE:
3023 case XML_ENTITY_NODE:
3024 case XML_PI_NODE:
3025 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003026 case XML_NOTATION_NODE:
3027 if (content != NULL) {
3028#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003029 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003030#else
3031 xmlBufferAdd(cur->content, content, len);
3032#endif
3033 }
Daniel Veillard16253641998-10-28 22:58:05 +00003034 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003035 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003036 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003037 case XML_DOCUMENT_TYPE_NODE:
3038 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003039 case XML_ELEMENT_DECL:
3040 case XML_ATTRIBUTE_DECL:
3041 case XML_ENTITY_DECL:
3042 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003043 }
3044}
3045
3046/**
3047 * xmlNodeAddContent:
3048 * @cur: the node being modified
3049 * @content: extra content
3050 *
3051 * Append the extra substring to the node content.
3052 */
3053void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003054xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003055 int len;
3056
3057 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003058#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00003059 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003060#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003061 return;
3062 }
Daniel Veillard16253641998-10-28 22:58:05 +00003063 if (content == NULL) return;
3064 len = xmlStrlen(content);
3065 xmlNodeAddContentLen(cur, content, len);
3066}
3067
3068/**
3069 * xmlTextMerge:
3070 * @first: the first text node
3071 * @second: the second text node being merged
3072 *
3073 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003074 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003075 */
3076xmlNodePtr
3077xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3078 if (first == NULL) return(second);
3079 if (second == NULL) return(first);
3080 if (first->type != XML_TEXT_NODE) return(first);
3081 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003082#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003083 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003084#else
3085 xmlNodeAddContent(first, xmlBufferContent(second->content));
3086#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003087 xmlUnlinkNode(second);
3088 xmlFreeNode(second);
3089 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003090}
3091
Daniel Veillard97b58771998-10-20 06:14:16 +00003092/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003093 * xmlGetNsList:
3094 * @doc: the document
3095 * @node: the current node
3096 *
3097 * Search all the namespace applying to a given element.
3098 * Returns an NULL terminated array of all the xmlNsPtr found
3099 * that need to be freed by the caller or NULL if no
3100 * namespace if defined
3101 */
3102xmlNsPtr *
3103xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3104 xmlNsPtr cur;
3105 xmlNsPtr *ret = NULL;
3106 int nbns = 0;
3107 int maxns = 10;
3108 int i;
3109
3110 while (node != NULL) {
3111 cur = node->nsDef;
3112 while (cur != NULL) {
3113 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003114 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003115 if (ret == NULL) {
3116 fprintf(stderr, "xmlGetNsList : out of memory!\n");
3117 return(NULL);
3118 }
3119 ret[nbns] = NULL;
3120 }
3121 for (i = 0;i < nbns;i++) {
3122 if ((cur->prefix == ret[i]->prefix) ||
3123 (!xmlStrcmp(cur->prefix, ret[i]->prefix))) break;
3124 }
3125 if (i >= nbns) {
3126 if (nbns >= maxns) {
3127 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003128 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003129 (maxns + 1) * sizeof(xmlNsPtr));
3130 if (ret == NULL) {
3131 fprintf(stderr, "xmlGetNsList : realloc failed!\n");
3132 return(NULL);
3133 }
3134 }
3135 ret[nbns++] = cur;
3136 ret[nbns] = NULL;
3137 }
3138
3139 cur = cur->next;
3140 }
3141 node = node->parent;
3142 }
3143 return(ret);
3144}
3145
3146/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003147 * xmlSearchNs:
3148 * @doc: the document
3149 * @node: the current node
3150 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003151 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003152 * Search a Ns registered under a given name space for a document.
3153 * recurse on the parents until it finds the defined namespace
3154 * or return NULL otherwise.
3155 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003156 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003157 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003158xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003159xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003160 xmlNsPtr cur;
3161
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003162 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003163 while (node != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003164 if (node->type == XML_ELEMENT_NODE) {
3165 cur = node->nsDef;
3166 while (cur != NULL) {
3167 if ((cur->prefix == NULL) && (nameSpace == NULL))
3168 return(cur);
3169 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3170 (!xmlStrcmp(cur->prefix, nameSpace)))
3171 return(cur);
3172 cur = cur->next;
3173 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003174 }
3175 node = node->parent;
3176 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003177 return(NULL);
3178}
3179
Daniel Veillard97b58771998-10-20 06:14:16 +00003180/**
3181 * xmlSearchNsByHref:
3182 * @doc: the document
3183 * @node: the current node
3184 * @href: the namespace value
3185 *
3186 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3187 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003188 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003189 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003190xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003191xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003192 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003193 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003194
Daniel Veillard10a2c651999-12-12 13:03:50 +00003195 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003196 while (node != NULL) {
3197 cur = node->nsDef;
3198 while (cur != NULL) {
3199 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003200 (!xmlStrcmp(cur->href, href))) {
3201 /*
3202 * Check that the prefix is not shadowed between orig and node
3203 */
3204 xmlNodePtr check = orig;
3205 xmlNsPtr tst;
3206
3207 while (check != node) {
3208 tst = check->nsDef;
3209 while (tst != NULL) {
3210 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3211 goto shadowed;
3212 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3213 (!xmlStrcmp(tst->prefix, cur->prefix)))
3214 goto shadowed;
3215 tst = tst->next;
3216 }
3217 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003218 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003219 }
3220shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003221 cur = cur->next;
3222 }
3223 node = node->parent;
3224 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003225 return(NULL);
3226}
3227
3228/**
3229 * xmlNewReconciliedNs
3230 * @doc: the document
3231 * @tree: a node expected to hold the new namespace
3232 * @ns: the original namespace
3233 *
3234 * This function tries to locate a namespace definition in a tree
3235 * ancestors, or create a new namespace definition node similar to
3236 * @ns trying to reuse the same prefix. However if the given prefix is
3237 * null (default namespace) or reused within the subtree defined by
3238 * @tree or on one of its ancestors then a new prefix is generated.
3239 * Returns the (new) namespace definition or NULL in case of error
3240 */
3241xmlNsPtr
3242xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3243 xmlNsPtr def;
3244 xmlChar prefix[50];
3245 int counter = 1;
3246
3247 if (tree == NULL) {
3248#ifdef DEBUG_TREE
3249 fprintf(stderr, "xmlNewReconciliedNs : tree == NULL\n");
3250#endif
3251 return(NULL);
3252 }
3253 if (ns == NULL) {
3254#ifdef DEBUG_TREE
3255 fprintf(stderr, "xmlNewReconciliedNs : ns == NULL\n");
3256#endif
3257 return(NULL);
3258 }
3259 /*
3260 * Search an existing namespace definition inherited.
3261 */
3262 def = xmlSearchNsByHref(doc, tree, ns->href);
3263 if (def != NULL)
3264 return(def);
3265
3266 /*
3267 * Find a close prefix which is not already in use.
3268 * Let's strip namespace prefixes longer than 20 chars !
3269 */
3270 sprintf((char *) prefix, "%.20s", ns->prefix);
3271 def = xmlSearchNs(doc, tree, prefix);
3272 while (def != NULL) {
3273 if (counter > 1000) return(NULL);
3274 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3275 def = xmlSearchNs(doc, tree, prefix);
3276 }
3277
3278 /*
3279 * Ok, now we are ready to create a new one.
3280 */
3281 def = xmlNewNs(tree, ns->href, prefix);
3282 return(def);
3283}
3284
3285/**
3286 * xmlReconciliateNs
3287 * @doc: the document
3288 * @tree: a node defining the subtree to reconciliate
3289 *
3290 * This function checks that all the namespaces declared within the given
3291 * tree are properly declared. This is needed for example after Copy or Cut
3292 * and then paste operations. The subtree may still hold pointers to
3293 * namespace declarations outside the subtree or invalid/masked. As much
3294 * as possible the function try tu reuse the existing namespaces found in
3295 * the new environment. If not possible the new namespaces are redeclared
3296 * on @tree at the top of the given subtree.
3297 * Returns the number of namespace declarations created or -1 in case of error.
3298 */
3299int
3300xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3301 xmlNsPtr *oldNs = NULL;
3302 xmlNsPtr *newNs = NULL;
3303 int sizeCache = 0;
3304 int nbCache = 0;
3305
3306 xmlNsPtr n;
3307 xmlNodePtr node = tree;
3308 xmlAttrPtr attr;
3309 int ret = 0, i;
3310
3311 while (node != NULL) {
3312 /*
3313 * Reconciliate the node namespace
3314 */
3315 if (node->ns != NULL) {
3316 /*
3317 * initialize the cache if needed
3318 */
3319 if (sizeCache == 0) {
3320 sizeCache = 10;
3321 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3322 sizeof(xmlNsPtr));
3323 if (oldNs == NULL) {
3324 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3325 return(-1);
3326 }
3327 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3328 sizeof(xmlNsPtr));
3329 if (newNs == NULL) {
3330 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3331 xmlFree(oldNs);
3332 return(-1);
3333 }
3334 }
3335 for (i = 0;i < nbCache;i++) {
3336 if (oldNs[i] == node->ns) {
3337 node->ns = newNs[i];
3338 break;
3339 }
3340 }
3341 if (i == nbCache) {
3342 /*
3343 * Ok we need to recreate a new namespace definition
3344 */
3345 n = xmlNewReconciliedNs(doc, tree, node->ns);
3346 if (n != NULL) { /* :-( what if else ??? */
3347 /*
3348 * check if we need to grow the cache buffers.
3349 */
3350 if (sizeCache <= nbCache) {
3351 sizeCache *= 2;
3352 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3353 sizeof(xmlNsPtr));
3354 if (oldNs == NULL) {
3355 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3356 xmlFree(newNs);
3357 return(-1);
3358 }
3359 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3360 sizeof(xmlNsPtr));
3361 if (newNs == NULL) {
3362 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3363 xmlFree(oldNs);
3364 return(-1);
3365 }
3366 }
3367 newNs[nbCache] = n;
3368 oldNs[nbCache++] = node->ns;
3369 node->ns = n;
3370 }
3371 }
3372 }
3373 /*
3374 * now check for namespace hold by attributes on the node.
3375 */
3376 attr = node->properties;
3377 while (attr != NULL) {
3378 if (attr->ns != NULL) {
3379 /*
3380 * initialize the cache if needed
3381 */
3382 if (sizeCache == 0) {
3383 sizeCache = 10;
3384 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3385 sizeof(xmlNsPtr));
3386 if (oldNs == NULL) {
3387 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3388 return(-1);
3389 }
3390 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3391 sizeof(xmlNsPtr));
3392 if (newNs == NULL) {
3393 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3394 xmlFree(oldNs);
3395 return(-1);
3396 }
3397 }
3398 for (i = 0;i < nbCache;i++) {
3399 if (oldNs[i] == attr->ns) {
3400 node->ns = newNs[i];
3401 break;
3402 }
3403 }
3404 if (i == nbCache) {
3405 /*
3406 * Ok we need to recreate a new namespace definition
3407 */
3408 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3409 if (n != NULL) { /* :-( what if else ??? */
3410 /*
3411 * check if we need to grow the cache buffers.
3412 */
3413 if (sizeCache <= nbCache) {
3414 sizeCache *= 2;
3415 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3416 sizeof(xmlNsPtr));
3417 if (oldNs == NULL) {
3418 fprintf(stderr,
3419 "xmlReconciliateNs : memory pbm\n");
3420 xmlFree(newNs);
3421 return(-1);
3422 }
3423 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3424 sizeof(xmlNsPtr));
3425 if (newNs == NULL) {
3426 fprintf(stderr,
3427 "xmlReconciliateNs : memory pbm\n");
3428 xmlFree(oldNs);
3429 return(-1);
3430 }
3431 }
3432 newNs[nbCache] = n;
3433 oldNs[nbCache++] = attr->ns;
3434 attr->ns = n;
3435 }
3436 }
3437 }
3438 attr = attr->next;
3439 }
3440
3441 /*
3442 * Browse the full subtree, deep first
3443 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003444 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003445 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003446 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003447 } else if ((node != tree) && (node->next != NULL)) {
3448 /* then siblings */
3449 node = node->next;
3450 } else if (node != tree) {
3451 /* go up to parents->next if needed */
3452 while (node != tree) {
3453 if (node->parent != NULL)
3454 node = node->parent;
3455 if ((node != tree) && (node->next != NULL)) {
3456 node = node->next;
3457 break;
3458 }
3459 if (node->parent == NULL) {
3460 node = NULL;
3461 break;
3462 }
3463 }
3464 /* exit condition */
3465 if (node == tree)
3466 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003467 }
3468 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003469 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003470}
3471
Daniel Veillard97b58771998-10-20 06:14:16 +00003472/**
3473 * xmlGetProp:
3474 * @node: the node
3475 * @name: the attribute name
3476 *
3477 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003478 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003479 * This function looks in DTD attribute declaration for #FIXED or
3480 * default declaration values unless DTD use has been turned off.
3481 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003482 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003483 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003484 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003485xmlChar *
3486xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003487 xmlAttrPtr prop;
3488 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003489
Daniel Veillard10a2c651999-12-12 13:03:50 +00003490 if ((node == NULL) || (name == NULL)) return(NULL);
3491 /*
3492 * Check on the properties attached to the node
3493 */
3494 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003495 while (prop != NULL) {
Daniel Veillard68178931999-02-08 18:34:36 +00003496 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003497 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00003498
Daniel Veillardcf461992000-03-14 18:30:20 +00003499 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003500 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00003501 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00003502 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003503 prop = prop->next;
3504 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003505 if (!xmlCheckDTD) return(NULL);
3506
3507 /*
3508 * Check if there is a default declaration in the internal
3509 * or external subsets
3510 */
3511 doc = node->doc;
3512 if (doc != NULL) {
3513 xmlAttributePtr attrDecl;
3514 if (doc->intSubset != NULL) {
3515 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3516 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3517 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00003518 if (attrDecl != NULL)
3519 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003520 }
3521 }
3522 return(NULL);
3523}
3524
3525/**
3526 * xmlGetNsProp:
3527 * @node: the node
3528 * @name: the attribute name
3529 * @namespace: the URI of the namespace
3530 *
3531 * Search and get the value of an attribute associated to a node
3532 * This attribute has to be anchored in the namespace specified.
3533 * This does the entity substitution.
3534 * This function looks in DTD attribute declaration for #FIXED or
3535 * default declaration values unless DTD use has been turned off.
3536 *
3537 * Returns the attribute value or NULL if not found.
3538 * It's up to the caller to free the memory.
3539 */
3540xmlChar *
3541xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
3542 xmlAttrPtr prop = node->properties;
3543 xmlDocPtr doc;
3544 xmlNsPtr ns;
3545
3546 if (namespace == NULL)
3547 return(xmlGetProp(node, name));
3548 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003549 /*
3550 * One need to have
3551 * - same attribute names
3552 * - and the attribute carrying that namespace
3553 * or
3554 * no namespace on the attribute and the element carrying it
3555 */
Daniel Veillard10a2c651999-12-12 13:03:50 +00003556 if ((!xmlStrcmp(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003557 (((prop->ns == NULL) && (node->ns != NULL) &&
3558 (!xmlStrcmp(node->ns->href, namespace))) ||
Daniel Veillard3c558c31999-12-22 11:30:41 +00003559 ((prop->ns != NULL) && (!xmlStrcmp(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003560 xmlChar *ret;
3561
Daniel Veillardcf461992000-03-14 18:30:20 +00003562 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00003563 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
3564 return(ret);
3565 }
3566 prop = prop->next;
3567 }
3568 if (!xmlCheckDTD) return(NULL);
3569
3570 /*
3571 * Check if there is a default declaration in the internal
3572 * or external subsets
3573 */
3574 doc = node->doc;
3575 if (doc != NULL) {
3576 xmlAttributePtr attrDecl;
3577 if (doc->intSubset != NULL) {
3578 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3579 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3580 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3581
3582 if (attrDecl->prefix != NULL) {
3583 /*
3584 * The DTD declaration only allows a prefix search
3585 */
3586 ns = xmlSearchNs(doc, node, attrDecl->prefix);
3587 if ((ns != NULL) && (!xmlStrcmp(ns->href, namespace)))
3588 return(xmlStrdup(attrDecl->defaultValue));
3589 }
3590 }
3591 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003592 return(NULL);
3593}
3594
Daniel Veillard97b58771998-10-20 06:14:16 +00003595/**
Daniel Veillardccb09631998-10-27 06:21:04 +00003596 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00003597 * @node: the node
3598 * @name: the attribute name
3599 * @value: the attribute value
3600 *
3601 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003602 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003603 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003604xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003605xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003606 xmlAttrPtr prop = node->properties;
3607
3608 while (prop != NULL) {
3609 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003610 if (prop->children != NULL)
3611 xmlFreeNodeList(prop->children);
3612 prop->children = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00003613 if (value != NULL) {
3614 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00003615 xmlNodePtr tmp;
3616
Daniel Veillard51e3b151999-11-12 17:02:31 +00003617 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00003618 prop->children = xmlStringGetNodeList(node->doc, buffer);
3619 tmp = prop->children;
3620 while (tmp != NULL) {
3621 tmp->parent = (xmlNodePtr) prop;
3622 if (tmp->next == NULL)
3623 prop->last = tmp;
3624 tmp = tmp->next;
3625 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00003626 xmlFree(buffer);
3627 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003628 return(prop);
3629 }
3630 prop = prop->next;
3631 }
3632 prop = xmlNewProp(node, name, value);
3633 return(prop);
3634}
3635
Daniel Veillard97b58771998-10-20 06:14:16 +00003636/**
3637 * xmlNodeIsText:
3638 * @node: the node
3639 *
3640 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00003641 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00003642 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003643int
3644xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003645 if (node == NULL) return(0);
3646
Daniel Veillard0bef1311998-10-14 02:36:47 +00003647 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003648 return(0);
3649}
3650
Daniel Veillard97b58771998-10-20 06:14:16 +00003651/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00003652 * xmlIsBlankNode:
3653 * @node: the node
3654 *
3655 * Is this node a Text node ?
3656 * Returns 1 yes, 0 no
3657 */
3658int
3659xmlIsBlankNode(xmlNodePtr node) {
3660 xmlChar *cur;
3661 if (node == NULL) return(0);
3662
3663 if (node->type != XML_TEXT_NODE) return(0);
3664 if (node->content == NULL) return(0);
3665 cur = node->content;
3666 while (*cur != 0) {
3667 if (!IS_BLANK(*cur)) return(0);
3668 cur++;
3669 }
3670
3671 return(1);
3672}
3673
3674/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00003675 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00003676 * @node: the node
3677 * @content: the content
3678 * @len: @content lenght
3679 *
3680 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00003681 */
Daniel Veillard97b58771998-10-20 06:14:16 +00003682
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003683void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003684xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003685 if (node == NULL) return;
3686
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003687 if ((node->type != XML_TEXT_NODE) &&
3688 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003689#ifdef DEBUG_TREE
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003690 fprintf(stderr, "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003691#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003692 return;
3693 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003694#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00003695 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003696#else
3697 xmlBufferAdd(node->content, content, len);
3698#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003699}
3700
3701/************************************************************************
3702 * *
3703 * Output : to a FILE or in memory *
3704 * *
3705 ************************************************************************/
3706
Daniel Veillard5099ae81999-04-21 20:12:07 +00003707#define BASE_BUFFER_SIZE 4000
3708
3709/**
3710 * xmlBufferCreate:
3711 *
3712 * routine to create an XML buffer.
3713 * returns the new structure.
3714 */
3715xmlBufferPtr
3716xmlBufferCreate(void) {
3717 xmlBufferPtr ret;
3718
Daniel Veillard6454aec1999-09-02 22:04:43 +00003719 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00003720 if (ret == NULL) {
3721 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3722 return(NULL);
3723 }
3724 ret->use = 0;
3725 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003726 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003727 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00003728 if (ret->content == NULL) {
3729 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00003730 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003731 return(NULL);
3732 }
3733 ret->content[0] = 0;
3734 return(ret);
3735}
3736
3737/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003738 * xmlBufferCreateSize:
3739 * @size: initial size of buffer
3740 *
3741 * routine to create an XML buffer.
3742 * returns the new structure.
3743 */
3744xmlBufferPtr
3745xmlBufferCreateSize(size_t size) {
3746 xmlBufferPtr ret;
3747
3748 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
3749 if (ret == NULL) {
3750 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3751 return(NULL);
3752 }
3753 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003754 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003755 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00003756 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003757 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
3758 if (ret->content == NULL) {
3759 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3760 xmlFree(ret);
3761 return(NULL);
3762 }
3763 ret->content[0] = 0;
3764 } else
3765 ret->content = NULL;
3766 return(ret);
3767}
3768
3769/**
Daniel Veillard06047432000-04-24 11:33:38 +00003770 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003771 * @buf: the buffer to free
3772 * @scheme: allocation scheme to use
3773 *
3774 * Sets the allocation scheme for this buffer
3775 */
3776void
3777xmlBufferSetAllocationScheme(xmlBufferPtr buf,
3778 xmlBufferAllocationScheme scheme) {
3779 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003780#ifdef DEBUG_BUFFER
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003781 fprintf(stderr, "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003782#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003783 return;
3784 }
3785
3786 buf->alloc = scheme;
3787}
3788
3789/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00003790 * xmlBufferFree:
3791 * @buf: the buffer to free
3792 *
3793 * Frees an XML buffer.
3794 */
3795void
3796xmlBufferFree(xmlBufferPtr buf) {
3797 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003798#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00003799 fprintf(stderr, "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003800#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00003801 return;
3802 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003803 if (buf->content != NULL) {
3804#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00003805 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003806#else
3807 memset(buf->content, -1, buf->size);
3808#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00003809 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003810 }
3811 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003812 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003813}
3814
3815/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003816 * xmlBufferEmpty:
3817 * @buf: the buffer
3818 *
3819 * empty a buffer.
3820 */
3821void
3822xmlBufferEmpty(xmlBufferPtr buf) {
3823 buf->use = 0;
3824 memset(buf->content, -1, buf->size);/* just for debug */
3825}
3826
3827/**
3828 * xmlBufferShrink:
3829 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003830 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003831 *
3832 * Remove the beginning of an XML buffer.
3833 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003834 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003835 */
3836int
3837xmlBufferShrink(xmlBufferPtr buf, int len) {
3838 if (len == 0) return(0);
3839 if (len > buf->use) return(-1);
3840
3841 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003842 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003843
3844 buf->content[buf->use] = 0;
3845 return(len);
3846}
3847
3848/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00003849 * xmlBufferGrow:
3850 * @buf: the buffer
3851 * @len: the minimum free sie to allocate
3852 *
3853 * Grow the available space of an XML buffer.
3854 *
3855 * Returns the new available space or -1 in case of error
3856 */
3857int
3858xmlBufferGrow(xmlBufferPtr buf, int len) {
3859 int size;
3860 xmlChar *newbuf;
3861
3862 if (len <= buf->use) return(0);
3863
Daniel Veillardbe803962000-06-28 23:40:59 +00003864 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00003865
3866 newbuf = xmlRealloc(buf->content, size);
3867 if (newbuf == NULL) return(-1);
3868 buf->content = newbuf;
3869 buf->size = size;
3870 return(buf->size - buf->use);
3871}
3872
3873/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00003874 * xmlBufferDump:
3875 * @file: the file output
3876 * @buf: the buffer to dump
3877 *
3878 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003879 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00003880 */
3881int
3882xmlBufferDump(FILE *file, xmlBufferPtr buf) {
3883 int ret;
3884
3885 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003886#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00003887 fprintf(stderr, "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003888#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00003889 return(0);
3890 }
3891 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003892#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00003893 fprintf(stderr, "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003894#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00003895 return(0);
3896 }
3897 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003898 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003899 return(ret);
3900}
3901
3902/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003903 * xmlBufferContent:
3904 * @buf: the buffer to resize
3905 *
3906 * Returns the internal content
3907 */
3908
3909const xmlChar*
3910xmlBufferContent(const xmlBufferPtr buf)
3911{
3912 if(!buf)
3913 return NULL;
3914
3915 return buf->content;
3916}
3917
3918/**
3919 * xmlBufferLength:
3920 * @buf: the buffer
3921 *
3922 * Returns the length of data in the internal content
3923 */
3924
3925int
3926xmlBufferLength(const xmlBufferPtr buf)
3927{
3928 if(!buf)
3929 return 0;
3930
3931 return buf->use;
3932}
3933
3934/**
3935 * xmlBufferResize:
3936 * @buf: the buffer to resize
3937 * @len: the desired size
3938 *
3939 * Resize a buffer to accomodate minimum size of <len>.
3940 *
3941 * Returns 0 in case of problems, 1 otherwise
3942 */
3943int
3944xmlBufferResize(xmlBufferPtr buf, int size)
3945{
3946 int newSize = (buf->size ? buf->size*2 : size);/*take care of empty case*/
3947 xmlChar* rebuf = NULL;
3948
3949 /* Don't resize if we don't have to */
3950 if(size < buf->size)
3951 return 1;
3952
3953 /* figure out new size */
3954 switch(buf->alloc){
3955 case XML_BUFFER_ALLOC_DOUBLEIT:
3956 while(size > newSize) newSize *= 2;
3957 break;
3958 case XML_BUFFER_ALLOC_EXACT:
3959 newSize = size+10;
3960 break;
3961 default:
3962 newSize = size+10;
3963 break;
3964 }
3965
3966 if (buf->content == NULL)
3967 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
3968 else
3969 rebuf = (xmlChar *) xmlRealloc(buf->content,
3970 newSize * sizeof(xmlChar));
3971 if (rebuf == NULL) {
3972 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
3973 return 0;
3974 }
3975 buf->content = rebuf;
3976 buf->size = newSize;
3977
3978 return 1;
3979}
3980/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00003981 * xmlBufferAdd:
3982 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003983 * @str: the xmlChar string
3984 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00003985 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00003986 * Add a string range to an XML buffer. if len == -1, the lenght of
3987 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003988 */
3989void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003990xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003991 int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00003992
3993 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003994#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00003995 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003996#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00003997 return;
3998 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003999 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004000#ifdef DEBUG_BUFFER
Daniel Veillard10a2c651999-12-12 13:03:50 +00004001 fprintf(stderr, "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004002#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004003 return;
4004 }
4005 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004006
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004007 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004008 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004009
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004010 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004011
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004012 needSize = buf->use + len + 2;
4013 if(needSize > buf->size){
4014 if(!xmlBufferResize(buf, needSize)){
4015 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
4016 return;
4017 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004018 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004019
4020 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004021 buf->use += len;
4022 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004023}
4024
4025/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004026 * xmlBufferAddHead:
4027 * @buf: the buffer
4028 * @str: the xmlChar string
4029 * @len: the number of xmlChar to add
4030 *
4031 * Add a string range to the beginning of an XML buffer.
4032 * if len == -1, the lenght of @str is recomputed.
4033 */
4034void
4035xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
4036 int needSize;
4037
4038 if (str == NULL) {
4039#ifdef DEBUG_BUFFER
4040 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
4041#endif
4042 return;
4043 }
4044 if (len < -1) {
4045#ifdef DEBUG_BUFFER
4046 fprintf(stderr, "xmlBufferAdd: len < 0\n");
4047#endif
4048 return;
4049 }
4050 if (len == 0) return;
4051
4052 if (len < 0)
4053 len = xmlStrlen(str);
4054
4055 if (len <= 0) return;
4056
4057 needSize = buf->use + len + 2;
4058 if(needSize > buf->size){
4059 if(!xmlBufferResize(buf, needSize)){
4060 fprintf(stderr, "xmlBufferAddHead : out of memory!\n");
4061 return;
4062 }
4063 }
4064
4065 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4066 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4067 buf->use += len;
4068 buf->content[buf->use] = 0;
4069}
4070
4071/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004072 * xmlBufferCat:
4073 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004074 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004075 *
4076 * Append a zero terminated string to an XML buffer.
4077 */
4078void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004079xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004080 if (str != NULL)
4081 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004082}
4083
4084/**
4085 * xmlBufferCCat:
4086 * @buf: the buffer to dump
4087 * @str: the C char string
4088 *
4089 * Append a zero terminated C string to an XML buffer.
4090 */
4091void
4092xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4093 const char *cur;
4094
4095 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004096#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00004097 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004098#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004099 return;
4100 }
4101 for (cur = str;*cur != 0;cur++) {
4102 if (buf->use + 10 >= buf->size) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004103 if(!xmlBufferResize(buf, buf->use+10)){
4104 fprintf(stderr, "xmlBufferCCat : out of memory!\n");
4105 return;
4106 }
4107 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004108 buf->content[buf->use++] = *cur;
4109 }
4110}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004111
Daniel Veillard97b58771998-10-20 06:14:16 +00004112/**
4113 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004114 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004115 * @string: the string to add
4116 *
4117 * routine which manage and grows an output buffer. This one add
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004118 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004119 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004120void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004121xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004122 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004123}
4124
Daniel Veillard97b58771998-10-20 06:14:16 +00004125/**
4126 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004127 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004128 * @string: the string to add
4129 *
4130 * routine which manage and grows an output buffer. This one add
4131 * C chars at the end of the array.
4132 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004133void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004134xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4135 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004136}
4137
Daniel Veillard5099ae81999-04-21 20:12:07 +00004138
Daniel Veillard97b58771998-10-20 06:14:16 +00004139/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004140 * xmlBufferWriteQuotedString:
4141 * @buf: the XML buffer output
4142 * @string: the string to add
4143 *
4144 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004145 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004146 * quote or double-quotes internally
4147 */
4148void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004149xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004150 if (xmlStrchr(string, '"')) {
4151 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004152#ifdef DEBUG_BUFFER
Daniel Veillard011b63c1999-06-02 17:44:04 +00004153 fprintf(stderr,
4154 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004155#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004156 }
4157 xmlBufferCCat(buf, "'");
4158 xmlBufferCat(buf, string);
4159 xmlBufferCCat(buf, "'");
4160 } else {
4161 xmlBufferCCat(buf, "\"");
4162 xmlBufferCat(buf, string);
4163 xmlBufferCCat(buf, "\"");
4164 }
4165}
4166
4167
Daniel Veillardbe803962000-06-28 23:40:59 +00004168/************************************************************************
4169 * *
4170 * Dumping XML tree content to a simple buffer *
4171 * *
4172 ************************************************************************/
4173
Daniel Veillardcf461992000-03-14 18:30:20 +00004174static void
4175xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4176 int format);
4177static void
4178xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4179 int format);
4180void
4181htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4182
Daniel Veillard011b63c1999-06-02 17:44:04 +00004183/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004184 * xmlGlobalNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004185 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004186 * @cur: a namespace
4187 *
4188 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004189 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004190static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004191xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004192 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004193#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004194 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004195#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004196 return;
4197 }
4198 if (cur->type == XML_GLOBAL_NAMESPACE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004199 xmlBufferWriteChar(buf, "<?namespace");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004200 if (cur->href != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004201 xmlBufferWriteChar(buf, " href=");
4202 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004203 }
4204 if (cur->prefix != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004205 xmlBufferWriteChar(buf, " AS=");
4206 xmlBufferWriteQuotedString(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004207 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004208 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004209 }
4210}
4211
Daniel Veillard97b58771998-10-20 06:14:16 +00004212/**
4213 * xmlGlobalNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004214 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004215 * @cur: the first namespace
4216 *
4217 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004218 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004219static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004220xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004221 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004222 xmlGlobalNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004223 cur = cur->next;
4224 }
4225}
4226
Daniel Veillard97b58771998-10-20 06:14:16 +00004227/**
4228 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004229 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004230 * @cur: a namespace
4231 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004232 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004233 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004234 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004235static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004236xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004237 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004238#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004239 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004240#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004241 return;
4242 }
4243 if (cur->type == XML_LOCAL_NAMESPACE) {
4244 /* Within the context of an element attributes */
4245 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004246 xmlBufferWriteChar(buf, " xmlns:");
4247 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004248 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004249 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004250 xmlBufferWriteChar(buf, "=");
4251 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004252 }
4253}
4254
Daniel Veillard97b58771998-10-20 06:14:16 +00004255/**
4256 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004257 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004258 * @cur: the first namespace
4259 *
4260 * Dump a list of local Namespace definitions.
4261 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004262 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004263static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004264xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004265 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004266 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004267 cur = cur->next;
4268 }
4269}
4270
Daniel Veillard97b58771998-10-20 06:14:16 +00004271/**
4272 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004273 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004274 * @doc: the document
4275 *
4276 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004277 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004278static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004279xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4280 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004281#ifdef DEBUG_TREE
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004282 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004283#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004284 return;
4285 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004286 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004287 xmlBufferWriteCHAR(buf, dtd->name);
4288 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004289 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004290 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004291 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004292 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4293 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004294 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004295 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004296 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004297 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4298 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4299 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004300 return;
4301 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004302 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004303 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4304#if 0
4305 if (dtd->entities != NULL)
4306 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4307 if (dtd->notations != NULL)
4308 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4309 if (dtd->elements != NULL)
4310 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4311 if (dtd->attributes != NULL)
4312 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4313#endif
4314 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004315}
4316
Daniel Veillard97b58771998-10-20 06:14:16 +00004317/**
4318 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004319 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004320 * @doc: the document
4321 * @cur: the attribute pointer
4322 *
4323 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004324 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004325static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004326xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004327 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004328
Daniel Veillard260a68f1998-08-13 03:39:55 +00004329 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004330#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004331 fprintf(stderr, "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004332#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004333 return;
4334 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004335 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004336 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4337 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4338 xmlBufferWriteChar(buf, ":");
4339 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004340 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004341 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardccb09631998-10-27 06:21:04 +00004342 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004343 xmlBufferWriteChar(buf, "=");
4344 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004345 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004346 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004347 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004348 }
4349}
4350
Daniel Veillard97b58771998-10-20 06:14:16 +00004351/**
4352 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004353 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004354 * @doc: the document
4355 * @cur: the first attribute pointer
4356 *
4357 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004358 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004359static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004360xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004361 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004362#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004363 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004364#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004365 return;
4366 }
4367 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004368 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004369 cur = cur->next;
4370 }
4371}
4372
Daniel Veillard260a68f1998-08-13 03:39:55 +00004373
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004374
Daniel Veillard97b58771998-10-20 06:14:16 +00004375/**
4376 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004377 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004378 * @doc: the document
4379 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004380 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004381 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004382 *
4383 * Dump an XML node list, recursive behaviour,children are printed too.
4384 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004385static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004386xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4387 int format) {
4388 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004389
Daniel Veillard260a68f1998-08-13 03:39:55 +00004390 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004391#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004392 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004393#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004394 return;
4395 }
4396 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004397 if ((format) && (xmlIndentTreeOutput) &&
4398 (cur->type == XML_ELEMENT_NODE))
4399 for (i = 0;i < level;i++)
4400 xmlBufferWriteChar(buf, " ");
4401 xmlNodeDump(buf, doc, cur, level, format);
4402 if (format) {
4403 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004404 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004405 cur = cur->next;
4406 }
4407}
4408
Daniel Veillard97b58771998-10-20 06:14:16 +00004409/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004410 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004411 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004412 * @doc: the document
4413 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004414 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004415 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004416 *
4417 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004418 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004419static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004420xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4421 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004422 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004423 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004424
4425 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004426#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004427 fprintf(stderr, "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004428#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004429 return;
4430 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004431 if (cur->type == XML_DTD_NODE) {
4432 xmlDtdDump(buf, (xmlDtdPtr) cur);
4433 return;
4434 }
4435 if (cur->type == XML_ELEMENT_DECL) {
4436 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
4437 return;
4438 }
4439 if (cur->type == XML_ATTRIBUTE_DECL) {
4440 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
4441 return;
4442 }
4443 if (cur->type == XML_ENTITY_DECL) {
4444 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
4445 return;
4446 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004447 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00004448 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004449 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004450
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004451#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004452 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004453#else
4454 buffer = xmlEncodeEntitiesReentrant(doc,
4455 xmlBufferContent(cur->content));
4456#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004457 if (buffer != NULL) {
4458 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004459 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004460 }
4461 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004462 return;
4463 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004464 if (cur->type == XML_PI_NODE) {
4465 if (cur->content != NULL) {
4466 xmlBufferWriteChar(buf, "<?");
4467 xmlBufferWriteCHAR(buf, cur->name);
4468 if (cur->content != NULL) {
4469 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004470#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00004471 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004472#else
4473 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4474#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00004475 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004476 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00004477 } else {
4478 xmlBufferWriteChar(buf, "<?");
4479 xmlBufferWriteCHAR(buf, cur->name);
4480 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004481 }
4482 return;
4483 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004484 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004485 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004486 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004487#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004488 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004489#else
4490 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4491#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004492 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004493 }
4494 return;
4495 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004496 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004497 xmlBufferWriteChar(buf, "&");
4498 xmlBufferWriteCHAR(buf, cur->name);
4499 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00004500 return;
4501 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004502 if (cur->type == XML_CDATA_SECTION_NODE) {
4503 xmlBufferWriteChar(buf, "<![CDATA[");
4504 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004505#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00004506 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004507#else
4508 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4509#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00004510 xmlBufferWriteChar(buf, "]]>");
4511 return;
4512 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004513
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004514 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004515 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004516 while (tmp != NULL) {
4517 if ((tmp->type == XML_TEXT_NODE) ||
4518 (tmp->type == XML_ENTITY_REF_NODE)) {
4519 format = 0;
4520 break;
4521 }
4522 tmp = tmp->next;
4523 }
4524 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004525 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004526 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004527 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4528 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004529 }
4530
Daniel Veillard5099ae81999-04-21 20:12:07 +00004531 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004532 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004533 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004534 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004535 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004536
Daniel Veillardcf461992000-03-14 18:30:20 +00004537 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00004538 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004539 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004540 return;
4541 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004542 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00004543 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004544 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004545
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004546#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004547 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004548#else
4549 buffer = xmlEncodeEntitiesReentrant(doc,
4550 xmlBufferContent(cur->content));
4551#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004552 if (buffer != NULL) {
4553 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004554 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004555 }
4556 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004557 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004558 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004559 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004560 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004561 if ((xmlIndentTreeOutput) && (format))
4562 for (i = 0;i < level;i++)
4563 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004564 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004565 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004566 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004567 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4568 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004569 }
4570
Daniel Veillard5099ae81999-04-21 20:12:07 +00004571 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004572 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004573}
4574
Daniel Veillard97b58771998-10-20 06:14:16 +00004575/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004576 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00004577 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004578 * @doc: the document
4579 * @cur: the current node
4580 *
4581 * Dump an XML/HTML node, recursive behaviour,children are printed too.
4582 */
4583void
4584xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
4585 xmlBufferPtr buf;
4586
4587 if (cur == NULL) {
4588#ifdef DEBUG_TREE
4589 fprintf(stderr, "xmlElemDump : cur == NULL\n");
4590#endif
4591 return;
4592 }
4593 if (doc == NULL) {
4594#ifdef DEBUG_TREE
4595 fprintf(stderr, "xmlElemDump : doc == NULL\n");
4596#endif
4597 }
4598 buf = xmlBufferCreate();
4599 if (buf == NULL) return;
4600 if ((doc != NULL) &&
4601 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00004602#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004603 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00004604#else
4605 printf("HTML support not compiled in\n");
4606#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004607 } else
4608 xmlNodeDump(buf, doc, cur, 0, 1);
4609 xmlBufferDump(f, buf);
4610 xmlBufferFree(buf);
4611}
4612
4613/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004614 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004615 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004616 * @cur: the document
4617 *
4618 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004619 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004620static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004621xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00004622 xmlBufferWriteChar(buf, "<?xml version=");
4623 if (cur->version != NULL)
4624 xmlBufferWriteQuotedString(buf, cur->version);
4625 else
4626 xmlBufferWriteChar(buf, "\"1.0\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004627 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004628 xmlBufferWriteChar(buf, " encoding=");
4629 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004630 }
4631 switch (cur->standalone) {
4632 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004633 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004634 break;
4635 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004636 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004637 break;
4638 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004639 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004640 if (cur->children != NULL) {
4641 xmlNodePtr child = cur->children;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004642
Daniel Veillard260a68f1998-08-13 03:39:55 +00004643 /* global namespace definitions, the old way */
4644 if (oldXMLWDcompatibility)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004645 xmlGlobalNsListDump(buf, cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004646 else
4647 xmlUpgradeOldNs(cur);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004648
4649 while (child != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004650 xmlNodeDump(buf, cur, child, 0, 1);
4651 xmlBufferWriteChar(buf, "\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004652 child = child->next;
4653 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004654 }
4655}
4656
Daniel Veillardbe803962000-06-28 23:40:59 +00004657/************************************************************************
4658 * *
4659 * Dumping XML tree content to an I/O output buffer *
4660 * *
4661 ************************************************************************/
4662
4663static void
4664xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
4665 int level, int format, const char *encoding);
4666static void
4667xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
4668 int level, int format, const char *encoding);
4669/**
4670 * xmlGlobalNsDumpOutput:
4671 * @buf: the XML buffer output
4672 * @cur: a namespace
4673 *
4674 * Dump a global Namespace, this is the old version based on PIs.
4675 */
4676static void
4677xmlGlobalNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4678 if (cur == NULL) {
4679#ifdef DEBUG_TREE
4680 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
4681#endif
4682 return;
4683 }
4684 if (cur->type == XML_GLOBAL_NAMESPACE) {
4685 xmlOutputBufferWriteString(buf, "<?namespace");
4686 if (cur->href != NULL) {
4687 xmlOutputBufferWriteString(buf, " href=");
4688 xmlBufferWriteQuotedString(buf->buffer, cur->href);
4689 }
4690 if (cur->prefix != NULL) {
4691 xmlOutputBufferWriteString(buf, " AS=");
4692 xmlBufferWriteQuotedString(buf->buffer, cur->prefix);
4693 }
4694 xmlOutputBufferWriteString(buf, "?>\n");
4695 }
4696}
4697
4698/**
4699 * xmlGlobalNsListDumpOutput:
4700 * @buf: the XML buffer output
4701 * @cur: the first namespace
4702 *
4703 * Dump a list of global Namespace, this is the old version based on PIs.
4704 */
4705static void
4706xmlGlobalNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4707 while (cur != NULL) {
4708 xmlGlobalNsDumpOutput(buf, cur);
4709 cur = cur->next;
4710 }
4711}
4712
4713/**
4714 * xmlNsDumpOutput:
4715 * @buf: the XML buffer output
4716 * @cur: a namespace
4717 *
4718 * Dump a local Namespace definition.
4719 * Should be called in the context of attributes dumps.
4720 */
4721static void
4722xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4723 if (cur == NULL) {
4724#ifdef DEBUG_TREE
4725 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
4726#endif
4727 return;
4728 }
4729 if (cur->type == XML_LOCAL_NAMESPACE) {
4730 /* Within the context of an element attributes */
4731 if (cur->prefix != NULL) {
4732 xmlOutputBufferWriteString(buf, " xmlns:");
4733 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
4734 } else
4735 xmlOutputBufferWriteString(buf, " xmlns");
4736 xmlOutputBufferWriteString(buf, "=");
4737 xmlBufferWriteQuotedString(buf->buffer, cur->href);
4738 }
4739}
4740
4741/**
4742 * xmlNsListDumpOutput:
4743 * @buf: the XML buffer output
4744 * @cur: the first namespace
4745 *
4746 * Dump a list of local Namespace definitions.
4747 * Should be called in the context of attributes dumps.
4748 */
4749static void
4750xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4751 while (cur != NULL) {
4752 xmlNsDumpOutput(buf, cur);
4753 cur = cur->next;
4754 }
4755}
4756
4757/**
4758 * xmlDtdDumpOutput:
4759 * @buf: the XML buffer output
4760 * @doc: the document
4761 * @encoding: an optional encoding string
4762 *
4763 * Dump the XML document DTD, if any.
4764 */
4765static void
4766xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
4767 if (dtd == NULL) {
4768#ifdef DEBUG_TREE
4769 fprintf(stderr, "xmlDtdDump : no internal subset\n");
4770#endif
4771 return;
4772 }
4773 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
4774 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
4775 if (dtd->ExternalID != NULL) {
4776 xmlOutputBufferWriteString(buf, " PUBLIC ");
4777 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
4778 xmlOutputBufferWriteString(buf, " ");
4779 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
4780 } else if (dtd->SystemID != NULL) {
4781 xmlOutputBufferWriteString(buf, " SYSTEM ");
4782 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
4783 }
4784 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4785 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4786 xmlOutputBufferWriteString(buf, ">");
4787 return;
4788 }
4789 xmlOutputBufferWriteString(buf, " [\n");
4790 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
4791#if 0
4792 if (dtd->entities != NULL)
4793 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4794 if (dtd->notations != NULL)
4795 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4796 if (dtd->elements != NULL)
4797 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4798 if (dtd->attributes != NULL)
4799 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4800#endif
4801 xmlOutputBufferWriteString(buf, "]>");
4802}
4803
4804/**
4805 * xmlAttrDumpOutput:
4806 * @buf: the XML buffer output
4807 * @doc: the document
4808 * @cur: the attribute pointer
4809 * @encoding: an optional encoding string
4810 *
4811 * Dump an XML attribute
4812 */
4813static void
4814xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
4815 const char *encoding) {
4816 xmlChar *value;
4817
4818 if (cur == NULL) {
4819#ifdef DEBUG_TREE
4820 fprintf(stderr, "xmlAttrDump : property == NULL\n");
4821#endif
4822 return;
4823 }
4824 xmlOutputBufferWriteString(buf, " ");
4825 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4826 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
4827 xmlOutputBufferWriteString(buf, ":");
4828 }
4829 xmlOutputBufferWriteString(buf, (const char *)cur->name);
4830 value = xmlNodeListGetString(doc, cur->children, 0);
4831 if (value) {
4832 xmlOutputBufferWriteString(buf, "=");
4833 xmlBufferWriteQuotedString(buf->buffer, value);
4834 xmlFree(value);
4835 } else {
4836 xmlOutputBufferWriteString(buf, "=\"\"");
4837 }
4838}
4839
4840/**
4841 * xmlAttrListDumpOutput:
4842 * @buf: the XML buffer output
4843 * @doc: the document
4844 * @cur: the first attribute pointer
4845 * @encoding: an optional encoding string
4846 *
4847 * Dump a list of XML attributes
4848 */
4849static void
4850xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
4851 xmlAttrPtr cur, const char *encoding) {
4852 if (cur == NULL) {
4853#ifdef DEBUG_TREE
4854 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
4855#endif
4856 return;
4857 }
4858 while (cur != NULL) {
4859 xmlAttrDumpOutput(buf, doc, cur, encoding);
4860 cur = cur->next;
4861 }
4862}
4863
4864
4865
4866/**
4867 * xmlNodeListDumpOutput:
4868 * @buf: the XML buffer output
4869 * @doc: the document
4870 * @cur: the first node
4871 * @level: the imbrication level for indenting
4872 * @format: is formatting allowed
4873 * @encoding: an optional encoding string
4874 *
4875 * Dump an XML node list, recursive behaviour,children are printed too.
4876 */
4877static void
4878xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
4879 xmlNodePtr cur, int level, int format, const char *encoding) {
4880 int i;
4881
4882 if (cur == NULL) {
4883#ifdef DEBUG_TREE
4884 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
4885#endif
4886 return;
4887 }
4888 while (cur != NULL) {
4889 if ((format) && (xmlIndentTreeOutput) &&
4890 (cur->type == XML_ELEMENT_NODE))
4891 for (i = 0;i < level;i++)
4892 xmlOutputBufferWriteString(buf, " ");
4893 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
4894 if (format) {
4895 xmlOutputBufferWriteString(buf, "\n");
4896 }
4897 cur = cur->next;
4898 }
4899}
4900
4901/**
4902 * xmlNodeDumpOutput:
4903 * @buf: the XML buffer output
4904 * @doc: the document
4905 * @cur: the current node
4906 * @level: the imbrication level for indenting
4907 * @format: is formatting allowed
4908 * @encoding: an optional encoding string
4909 *
4910 * Dump an XML node, recursive behaviour,children are printed too.
4911 */
4912static void
4913xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
4914 int level, int format, const char *encoding) {
4915 int i;
4916 xmlNodePtr tmp;
4917
4918 if (cur == NULL) {
4919#ifdef DEBUG_TREE
4920 fprintf(stderr, "xmlNodeDump : node == NULL\n");
4921#endif
4922 return;
4923 }
4924 if (cur->type == XML_DTD_NODE) {
4925 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
4926 return;
4927 }
4928 if (cur->type == XML_ELEMENT_DECL) {
4929 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
4930 return;
4931 }
4932 if (cur->type == XML_ATTRIBUTE_DECL) {
4933 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
4934 return;
4935 }
4936 if (cur->type == XML_ENTITY_DECL) {
4937 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
4938 return;
4939 }
4940 if (cur->type == XML_TEXT_NODE) {
4941 if (cur->content != NULL) {
4942 xmlChar *buffer;
4943
4944#ifndef XML_USE_BUFFER_CONTENT
4945 if (encoding == NULL)
4946 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
4947 else
4948 buffer = xmlEncodeSpecialChars(doc, cur->content);
4949#else
4950 if (encoding == NULL)
4951 buffer = xmlEncodeEntitiesReentrant(doc,
4952 xmlBufferContent(cur->content));
4953 else
4954 buffer = xmlEncodeSpecialChars(doc,
4955 xmlBufferContent(cur->content));
4956#endif
4957 if (buffer != NULL) {
4958 xmlOutputBufferWriteString(buf, (const char *)buffer);
4959 xmlFree(buffer);
4960 }
4961 }
4962 return;
4963 }
4964 if (cur->type == XML_PI_NODE) {
4965 if (cur->content != NULL) {
4966 xmlOutputBufferWriteString(buf, "<?");
4967 xmlOutputBufferWriteString(buf, (const char *)cur->name);
4968 if (cur->content != NULL) {
4969 xmlOutputBufferWriteString(buf, " ");
4970#ifndef XML_USE_BUFFER_CONTENT
4971 xmlOutputBufferWriteString(buf, (const char *)cur->content);
4972#else
4973 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
4974#endif
4975 }
4976 xmlOutputBufferWriteString(buf, "?>");
4977 } else {
4978 xmlOutputBufferWriteString(buf, "<?");
4979 xmlOutputBufferWriteString(buf, (const char *)cur->name);
4980 xmlOutputBufferWriteString(buf, "?>");
4981 }
4982 return;
4983 }
4984 if (cur->type == XML_COMMENT_NODE) {
4985 if (cur->content != NULL) {
4986 xmlOutputBufferWriteString(buf, "<!--");
4987#ifndef XML_USE_BUFFER_CONTENT
4988 xmlOutputBufferWriteString(buf, (const char *)cur->content);
4989#else
4990 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
4991#endif
4992 xmlOutputBufferWriteString(buf, "-->");
4993 }
4994 return;
4995 }
4996 if (cur->type == XML_ENTITY_REF_NODE) {
4997 xmlOutputBufferWriteString(buf, "&");
4998 xmlOutputBufferWriteString(buf, (const char *)cur->name);
4999 xmlOutputBufferWriteString(buf, ";");
5000 return;
5001 }
5002 if (cur->type == XML_CDATA_SECTION_NODE) {
5003 xmlOutputBufferWriteString(buf, "<![CDATA[");
5004 if (cur->content != NULL)
5005#ifndef XML_USE_BUFFER_CONTENT
5006 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5007#else
5008 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5009#endif
5010 xmlOutputBufferWriteString(buf, "]]>");
5011 return;
5012 }
5013
5014 if (format == 1) {
5015 tmp = cur->children;
5016 while (tmp != NULL) {
5017 if ((tmp->type == XML_TEXT_NODE) ||
5018 (tmp->type == XML_ENTITY_REF_NODE)) {
5019 format = 0;
5020 break;
5021 }
5022 tmp = tmp->next;
5023 }
5024 }
5025 xmlOutputBufferWriteString(buf, "<");
5026 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5027 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5028 xmlOutputBufferWriteString(buf, ":");
5029 }
5030
5031 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5032 if (cur->nsDef)
5033 xmlNsListDumpOutput(buf, cur->nsDef);
5034 if (cur->properties != NULL)
5035 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5036
5037 if ((cur->content == NULL) && (cur->children == NULL) &&
5038 (!xmlSaveNoEmptyTags)) {
5039 xmlOutputBufferWriteString(buf, "/>");
5040 return;
5041 }
5042 xmlOutputBufferWriteString(buf, ">");
5043 if (cur->content != NULL) {
5044 xmlChar *buffer;
5045
5046#ifndef XML_USE_BUFFER_CONTENT
5047 if (encoding == NULL)
5048 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5049 else
5050 buffer = xmlEncodeSpecialChars(doc, cur->content);
5051#else
5052 if (encoding == NULL)
5053 buffer = xmlEncodeEntitiesReentrant(doc,
5054 xmlBufferContent(cur->content));
5055 else
5056 buffer = xmlEncodeSpecialChars(doc,
5057 xmlBufferContent(cur->content));
5058#endif
5059 if (buffer != NULL) {
5060 xmlOutputBufferWriteString(buf, (const char *)buffer);
5061 xmlFree(buffer);
5062 }
5063 }
5064 if (cur->children != NULL) {
5065 if (format) xmlOutputBufferWriteString(buf, "\n");
5066 xmlNodeListDumpOutput(buf, doc, cur->children,
5067 (level >= 0?level+1:-1), format, encoding);
5068 if ((xmlIndentTreeOutput) && (format))
5069 for (i = 0;i < level;i++)
5070 xmlOutputBufferWriteString(buf, " ");
5071 }
5072 xmlOutputBufferWriteString(buf, "</");
5073 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5074 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5075 xmlOutputBufferWriteString(buf, ":");
5076 }
5077
5078 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5079 xmlOutputBufferWriteString(buf, ">");
5080}
5081
5082/**
5083 * xmlDocContentDumpOutput:
5084 * @buf: the XML buffer output
5085 * @cur: the document
5086 * @encoding: an optional encoding string
5087 *
5088 * Dump an XML document.
5089 */
5090static void
5091xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
5092 const char *encoding) {
5093 xmlOutputBufferWriteString(buf, "<?xml version=");
5094 if (cur->version != NULL)
5095 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5096 else
5097 xmlOutputBufferWriteString(buf, "\"1.0\"");
5098 if (encoding == NULL) {
5099 if (cur->encoding != NULL)
5100 encoding = (const char *) cur->encoding;
5101 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
5102 encoding = xmlGetCharEncodingName(cur->charset);
5103 }
5104 if (encoding != NULL) {
5105 xmlOutputBufferWriteString(buf, " encoding=");
5106 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5107 }
5108 switch (cur->standalone) {
5109 case 0:
5110 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5111 break;
5112 case 1:
5113 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5114 break;
5115 }
5116 xmlOutputBufferWriteString(buf, "?>\n");
5117 if (cur->children != NULL) {
5118 xmlNodePtr child = cur->children;
5119
5120 /* global namespace definitions, the old way */
5121 if (oldXMLWDcompatibility)
5122 xmlGlobalNsListDumpOutput(buf, cur->oldNs);
5123 else
5124 xmlUpgradeOldNs(cur);
5125
5126 while (child != NULL) {
5127 xmlNodeDumpOutput(buf, cur, child, 0, 1, encoding);
5128 xmlOutputBufferWriteString(buf, "\n");
5129 child = child->next;
5130 }
5131 }
5132}
5133
5134/************************************************************************
5135 * *
5136 * Saving functions front-ends *
5137 * *
5138 ************************************************************************/
5139
Daniel Veillard97b58771998-10-20 06:14:16 +00005140/**
5141 * xmlDocDumpMemory:
5142 * @cur: the document
5143 * @mem: OUT: the memory pointer
5144 * @size: OUT: the memory lenght
5145 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005146 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005147 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005148 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005149void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005150xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005151 xmlBufferPtr buf;
5152
Daniel Veillard260a68f1998-08-13 03:39:55 +00005153 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005154#ifdef DEBUG_TREE
5155 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
5156#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005157 *mem = NULL;
5158 *size = 0;
5159 return;
5160 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005161 buf = xmlBufferCreate();
5162 if (buf == NULL) {
5163 *mem = NULL;
5164 *size = 0;
5165 return;
5166 }
5167 xmlDocContentDump(buf, cur);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005168 *mem = xmlStrndup(buf->content, buf->use);
Daniel Veillard5099ae81999-04-21 20:12:07 +00005169 *size = buf->use;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005170 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005171}
5172
Daniel Veillard97b58771998-10-20 06:14:16 +00005173/**
5174 * xmlGetDocCompressMode:
5175 * @doc: the document
5176 *
5177 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005178 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005179 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005180int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005181xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005182 if (doc == NULL) return(-1);
5183 return(doc->compression);
5184}
5185
Daniel Veillard97b58771998-10-20 06:14:16 +00005186/**
5187 * xmlSetDocCompressMode:
5188 * @doc: the document
5189 * @mode: the compression ratio
5190 *
5191 * set the compression ratio for a document, ZLIB based
5192 * Correct values: 0 (uncompressed) to 9 (max compression)
5193 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005194void
5195xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005196 if (doc == NULL) return;
5197 if (mode < 0) doc->compression = 0;
5198 else if (mode > 9) doc->compression = 9;
5199 else doc->compression = mode;
5200}
5201
Daniel Veillard97b58771998-10-20 06:14:16 +00005202/**
5203 * xmlGetCompressMode:
5204 *
5205 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005206 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005207 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005208int
5209 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005210 return(xmlCompressMode);
5211}
Daniel Veillard97b58771998-10-20 06:14:16 +00005212
5213/**
5214 * xmlSetCompressMode:
5215 * @mode: the compression ratio
5216 *
5217 * set the default compression mode used, ZLIB based
5218 * Correct values: 0 (uncompressed) to 9 (max compression)
5219 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005220void
5221xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005222 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005223 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005224 else xmlCompressMode = mode;
5225}
5226
Daniel Veillardbe803962000-06-28 23:40:59 +00005227#if 0
Daniel Veillard97b58771998-10-20 06:14:16 +00005228/**
5229 * xmlDocDump:
5230 * @f: the FILE*
5231 * @cur: the document
5232 *
5233 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005234 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005235void
5236xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005237 xmlBufferPtr buf;
5238
Daniel Veillard260a68f1998-08-13 03:39:55 +00005239 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005240#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00005241 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005242#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005243 return;
5244 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005245 buf = xmlBufferCreate();
5246 if (buf == NULL) return;
5247 xmlDocContentDump(buf, cur);
5248 xmlBufferDump(f, buf);
5249 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005250}
5251
Daniel Veillard97b58771998-10-20 06:14:16 +00005252/**
5253 * xmlSaveFile:
5254 * @filename: the filename
5255 * @cur: the document
5256 *
5257 * Dump an XML document to a file. Will use compression if
Daniel Veillard11a48ec1999-11-23 10:40:46 +00005258 * compiled in and enabled. If @filename is "-" the stdout file is
5259 * used.
Daniel Veillard97b58771998-10-20 06:14:16 +00005260 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00005261 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005262int
5263xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005264 xmlBufferPtr buf;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005265#ifdef HAVE_ZLIB_H
5266 gzFile zoutput = NULL;
5267 char mode[15];
5268#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00005269 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005270 int ret;
5271
Daniel Veillard5099ae81999-04-21 20:12:07 +00005272 /*
5273 * save the content to a temp buffer.
5274 */
5275 buf = xmlBufferCreate();
5276 if (buf == NULL) return(0);
5277 xmlDocContentDump(buf, cur);
5278
Daniel Veillard151b1b01998-09-23 00:49:46 +00005279#ifdef HAVE_ZLIB_H
Daniel Veillard11a48ec1999-11-23 10:40:46 +00005280 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00005281 if ((cur->compression > 0) && (cur->compression <= 9)) {
5282 sprintf(mode, "w%d", cur->compression);
Daniel Veillard11a48ec1999-11-23 10:40:46 +00005283 if (!strcmp(filename, "-"))
5284 zoutput = gzdopen(1, mode);
5285 else
5286 zoutput = gzopen(filename, mode);
Daniel Veillard151b1b01998-09-23 00:49:46 +00005287 }
5288 if (zoutput == NULL) {
5289#endif
5290 output = fopen(filename, "w");
Daniel Veillard10a2c651999-12-12 13:03:50 +00005291 if (output == NULL) {
5292 xmlBufferFree(buf);
5293 return(-1);
5294 }
Daniel Veillard151b1b01998-09-23 00:49:46 +00005295#ifdef HAVE_ZLIB_H
5296 }
Daniel Veillard151b1b01998-09-23 00:49:46 +00005297
Daniel Veillard151b1b01998-09-23 00:49:46 +00005298 if (zoutput != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005299 ret = gzwrite(zoutput, buf->content, sizeof(xmlChar) * buf->use);
Daniel Veillard151b1b01998-09-23 00:49:46 +00005300 gzclose(zoutput);
Daniel Veillard5099ae81999-04-21 20:12:07 +00005301 } else {
5302#endif
5303 ret = xmlBufferDump(output, buf);
5304 fclose(output);
5305#ifdef HAVE_ZLIB_H
Daniel Veillard151b1b01998-09-23 00:49:46 +00005306 }
5307#endif
Manish Vachharajani5e60f5a1999-05-29 03:04:30 +00005308 xmlBufferFree(buf);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005309 return(ret * sizeof(xmlChar));
Daniel Veillard151b1b01998-09-23 00:49:46 +00005310}
Daniel Veillardbe803962000-06-28 23:40:59 +00005311#else
5312/**
5313 * xmlDocDump:
5314 * @f: the FILE*
5315 * @cur: the document
5316 *
5317 * Dump an XML document to an open FILE.
5318 *
5319 * returns: the number of file written or -1 in case of failure.
5320 */
5321int
5322xmlDocDump(FILE *f, xmlDocPtr cur) {
5323 xmlOutputBufferPtr buf;
5324 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005325
Daniel Veillardbe803962000-06-28 23:40:59 +00005326 if (cur == NULL) {
5327#ifdef DEBUG_TREE
5328 fprintf(stderr, "xmlDocDump : document == NULL\n");
5329#endif
5330 return(-1);
5331 }
5332 buf = xmlOutputBufferCreateFile(f, NULL);
5333 if (buf == NULL) return(-1);
5334 xmlDocContentDumpOutput(buf, cur, NULL);
5335
5336 ret = xmlOutputBufferClose(buf);
5337 return(ret);
5338}
5339
5340/**
5341 * xmlSaveFile:
5342 * @filename: the filename (or URL)
5343 * @cur: the document
5344 *
5345 * Dump an XML document to a file. Will use compression if
5346 * compiled in and enabled. If @filename is "-" the stdout file is
5347 * used.
5348 * returns: the number of file written or -1 in case of failure.
5349 */
5350int
5351xmlSaveFile(const char *filename, xmlDocPtr cur) {
5352 xmlOutputBufferPtr buf;
5353 int ret;
5354
5355 /*
5356 * save the content to a temp buffer.
5357 */
5358#ifdef HAVE_ZLIB_H
5359 if (cur->compression < 0) cur->compression = xmlCompressMode;
5360#endif
5361 buf = xmlOutputBufferCreateFilename(filename, NULL, cur->compression);
5362 if (buf == NULL) return(0);
5363
5364 xmlDocContentDumpOutput(buf, cur, NULL);
5365
5366 ret = xmlOutputBufferClose(buf);
5367 return(ret);
5368}
5369
5370/**
5371 * xmlSaveFileTo:
5372 * @buf: an output I/O buffer
5373 * @cur: the document
5374 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5375 *
5376 * Dump an XML document to an I/O buffer.
5377 *
5378 * returns: the number of file written or -1 in case of failure.
5379 */
5380int
5381xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5382 int ret;
5383
5384 if (buf == NULL) return(0);
5385 xmlDocContentDumpOutput(buf, cur, encoding);
5386 ret = xmlOutputBufferClose(buf);
5387 return(ret);
5388}
5389
5390/**
5391 * xmlSaveFileEnc:
5392 * @filename: the filename (or URL)
5393 * @cur: the document
5394 * @encoding: the name of an encoding (or NULL)
5395 *
5396 * Dump an XML document, converting it to the given encoding
5397 *
5398 * returns: the number of file written or -1 in case of failure.
5399 */
5400int
5401xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5402 xmlOutputBufferPtr buf;
5403 xmlCharEncodingHandlerPtr handler = NULL;
5404 int ret;
5405
5406 if (encoding != NULL) {
5407 xmlCharEncoding enc;
5408
5409 enc = xmlParseCharEncoding(encoding);
5410 if (enc != cur->charset) {
5411 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
5412 /*
5413 * Not supported yet
5414 */
5415 return(-1);
5416 }
5417
5418 handler = xmlFindCharEncodingHandler(encoding);
5419 if (handler == NULL)
5420 return(-1);
5421 }
5422 }
5423
5424 /*
5425 * save the content to a temp buffer.
5426 */
5427 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
5428 if (buf == NULL) return(0);
5429
5430 xmlDocContentDumpOutput(buf, cur, encoding);
5431
5432 ret = xmlOutputBufferClose(buf);
5433 return(ret);
5434}
5435#endif