blob: ee3584b62ff8318bc42fa249d42bb74f292d2d21 [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.
Daniel Veillarde0854c32000-08-27 21:12:29 +0000132 * We use href==NULL in the case of an element creation where the namespace
133 * was not defined.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000134 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000135 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000136xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000137xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000138 xmlNsPtr cur;
139
Daniel Veillard260a68f1998-08-13 03:39:55 +0000140 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000141 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000143 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000144 if (cur == NULL) {
145 fprintf(stderr, "xmlNewNs : malloc failed\n");
146 return(NULL);
147 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000148 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000149 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000150
Daniel Veillard260a68f1998-08-13 03:39:55 +0000151 if (href != NULL)
152 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000153 if (prefix != NULL)
154 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000155
156 /*
157 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000158 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000159 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000160 if (node != NULL) {
161 if (node->nsDef == NULL) {
162 node->nsDef = cur;
163 } else {
164 xmlNsPtr prev = node->nsDef;
165
Daniel Veillard0142b842000-01-14 14:45:24 +0000166 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000167 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000168 xmlFreeNs(cur);
169 return(NULL);
170 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000171 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000172 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000173 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000174 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard686d6b62000-01-03 11:08:02 +0000175 xmlFreeNs(cur);
176 return(NULL);
177 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000178 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000179 prev->next = cur;
180 }
181 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000182 return(cur);
183}
184
Daniel Veillard97b58771998-10-20 06:14:16 +0000185/**
186 * xmlNewGlobalNs:
187 * @doc: the document carrying the namespace
188 * @href: the URI associated
189 * @prefix: the prefix for the namespace
190 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000191 * Creation of a Namespace, the old way using PI and without scoping
192 * DEPRECATED !!!
Daniel Veillard0142b842000-01-14 14:45:24 +0000193 * It now create a namespace on the root element of the document if found.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000194 * Returns NULL this functionnality had been removed
Daniel Veillard260a68f1998-08-13 03:39:55 +0000195 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000196xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000197xmlNewGlobalNs(xmlDocPtr doc, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000198 xmlNodePtr root;
199
200 xmlNsPtr cur;
201
202 root = xmlDocGetRootElement(doc);
203 if (root != NULL)
204 return(xmlNewNs(root, href, prefix));
205
206 /*
207 * if there is no root element yet, create an old Namespace type
208 * and it will be moved to the root at save time.
209 */
210 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
211 if (cur == NULL) {
212 fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
213 return(NULL);
214 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000215 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard0142b842000-01-14 14:45:24 +0000216 cur->type = XML_GLOBAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000217
Daniel Veillard0142b842000-01-14 14:45:24 +0000218 if (href != NULL)
219 cur->href = xmlStrdup(href);
Daniel Veillard0142b842000-01-14 14:45:24 +0000220 if (prefix != NULL)
221 cur->prefix = xmlStrdup(prefix);
Daniel Veillard0142b842000-01-14 14:45:24 +0000222
223 /*
224 * Add it at the end to preserve parsing order ...
225 */
Daniel Veillard0142b842000-01-14 14:45:24 +0000226 if (doc != NULL) {
227 if (doc->oldNs == NULL) {
228 doc->oldNs = cur;
229 } else {
230 xmlNsPtr prev = doc->oldNs;
231
232 while (prev->next != NULL) prev = prev->next;
233 prev->next = cur;
234 }
235 }
236
237 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000238}
239
Daniel Veillard97b58771998-10-20 06:14:16 +0000240/**
241 * xmlSetNs:
242 * @node: a node in the document
243 * @ns: a namespace pointer
244 *
245 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000246 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000247void
248xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000249 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000250#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000251 fprintf(stderr, "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000252#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000253 return;
254 }
255 node->ns = ns;
256}
257
Daniel Veillard97b58771998-10-20 06:14:16 +0000258/**
259 * xmlFreeNs:
260 * @cur: the namespace pointer
261 *
262 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000263 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000264void
265xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000266 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000267#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000268 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000269#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000270 return;
271 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000272 if (cur->href != NULL) xmlFree((char *) cur->href);
273 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000274 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000275 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000276}
277
Daniel Veillard97b58771998-10-20 06:14:16 +0000278/**
279 * xmlFreeNsList:
280 * @cur: the first namespace pointer
281 *
282 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000283 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000284void
285xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000286 xmlNsPtr next;
287 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000288#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000289 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000290#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000291 return;
292 }
293 while (cur != NULL) {
294 next = cur->next;
295 xmlFreeNs(cur);
296 cur = next;
297 }
298}
299
Daniel Veillard97b58771998-10-20 06:14:16 +0000300/**
301 * xmlNewDtd:
302 * @doc: the document pointer
303 * @name: the DTD name
304 * @ExternalID: the external ID
305 * @SystemID: the system ID
306 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000307 * Creation of a new DTD for the external subset. To create an
308 * internal subset, use xmlCreateIntSubset().
309 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000310 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000311 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000312xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000313xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
314 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000315 xmlDtdPtr cur;
316
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000317 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000318#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000319 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000320 /* !!! */ (char *) name, doc->name,
321 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000322#endif
323 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000324 }
325
326 /*
327 * Allocate a new DTD and fill the fields.
328 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000329 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000330 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000331 fprintf(stderr, "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000332 return(NULL);
333 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000334 memset(cur, 0 , sizeof(xmlDtd));
335 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000336
337 if (name != NULL)
338 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000339 if (ExternalID != NULL)
340 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000341 if (SystemID != NULL)
342 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000343 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000344 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000345 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000346
347 return(cur);
348}
349
350/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000351 * xmlGetIntSubset:
352 * @doc: the document pointer
353 *
354 * Get the internal subset of a document
355 * Returns a pointer to the DTD structure or NULL if not found
356 */
357
358xmlDtdPtr
359xmlGetIntSubset(xmlDocPtr doc) {
360 xmlNodePtr cur;
361
362 if (doc == NULL)
363 return(NULL);
364 cur = doc->children;
365 while (cur != NULL) {
366 if (cur->type == XML_DTD_NODE)
367 return((xmlDtdPtr) cur);
368 cur = cur->next;
369 }
370 return((xmlDtdPtr) doc->intSubset);
371}
372
373/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000374 * xmlCreateIntSubset:
375 * @doc: the document pointer
376 * @name: the DTD name
377 * @ExternalID: the external ID
378 * @SystemID: the system ID
379 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000380 * Create the internal subset of a document
381 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000382 */
383xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000384xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
385 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000386 xmlDtdPtr cur;
387
Daniel Veillardcf461992000-03-14 18:30:20 +0000388 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000389#ifdef DEBUG_TREE
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000390 fprintf(stderr,
391 "xmlCreateIntSubset(): document %s already have an internal subset\n",
392 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000393#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000394 return(NULL);
395 }
396
397 /*
398 * Allocate a new DTD and fill the fields.
399 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000400 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000401 if (cur == NULL) {
402 fprintf(stderr, "xmlNewDtd : malloc failed\n");
403 return(NULL);
404 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000405 memset(cur, 0, sizeof(xmlDtd));
406 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000407
408 if (name != NULL)
409 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000410 if (ExternalID != NULL)
411 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000412 if (SystemID != NULL)
413 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000414 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000416 cur->parent = doc;
417 cur->doc = doc;
418 if (doc->children == NULL) {
419 doc->children = (xmlNodePtr) cur;
420 doc->last = (xmlNodePtr) cur;
421 } else {
422 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000423
Daniel Veillardb8f25c92000-08-19 19:52:36 +0000424 if (doc->type == XML_HTML_DOCUMENT_NODE) {
425 prev = doc->children;
426 prev->prev = (xmlNodePtr) cur;
427 cur->next = prev;
428 doc->children = (xmlNodePtr) cur;
429 } else {
430 prev = doc->last;
431 prev->next = (xmlNodePtr) cur;
432 cur->prev = prev;
433 doc->last = (xmlNodePtr) cur;
434 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000435 }
436 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000437 return(cur);
438}
439
Daniel Veillard97b58771998-10-20 06:14:16 +0000440/**
441 * xmlFreeDtd:
442 * @cur: the DTD structure to free up
443 *
444 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000445 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000446void
447xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000448 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000449#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000451#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000452 return;
453 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000454 if (cur->children != NULL) {
455 xmlNodePtr next, c = cur->children;
456
457 /*
458 * Cleanup all the DTD comments they are not in the Dtd
459 * indexes.
460 */
461 while (c != NULL) {
462 next = c->next;
463 if (c->type == XML_COMMENT_NODE) {
464 xmlUnlinkNode(c);
465 xmlFreeNode(c);
466 }
467 c = next;
468 }
469 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000470 if (cur->name != NULL) xmlFree((char *) cur->name);
471 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
472 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000473 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000474 if (cur->notations != NULL)
475 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000476
Daniel Veillard260a68f1998-08-13 03:39:55 +0000477 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000478 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000479 if (cur->attributes != NULL)
480 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000481 if (cur->entities != NULL)
482 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000483
Daniel Veillard260a68f1998-08-13 03:39:55 +0000484 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000485 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000486}
487
Daniel Veillard97b58771998-10-20 06:14:16 +0000488/**
489 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000490 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000491 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000492 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000493 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000494xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000495xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000496 xmlDocPtr cur;
497
498 if (version == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000499#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000500 fprintf(stderr, "xmlNewDoc : version == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000501#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000502 return(NULL);
503 }
504
505 /*
506 * Allocate a new document and fill the fields.
507 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000508 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000509 if (cur == NULL) {
510 fprintf(stderr, "xmlNewDoc : malloc failed\n");
511 return(NULL);
512 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000513 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000514 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000515
Daniel Veillard260a68f1998-08-13 03:39:55 +0000516 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000517 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000518 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000519 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000520 return(cur);
521}
522
Daniel Veillard97b58771998-10-20 06:14:16 +0000523/**
524 * xmlFreeDoc:
525 * @cur: pointer to the document
526 * @:
527 *
528 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000529 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000530void
531xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000532 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000533#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000534 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000535#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000536 return;
537 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000538 if (cur->version != NULL) xmlFree((char *) cur->version);
539 if (cur->name != NULL) xmlFree((char *) cur->name);
540 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000541 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000542 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
543 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000544 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000545 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000546 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000547 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000548 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000549 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000550}
551
Daniel Veillard97b58771998-10-20 06:14:16 +0000552/**
Daniel Veillard16253641998-10-28 22:58:05 +0000553 * xmlStringLenGetNodeList:
554 * @doc: the document
555 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000556 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000557 *
558 * Parse the value string and build the node list associated. Should
559 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000560 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000561 */
562xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000563xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000564 xmlNodePtr ret = NULL, last = NULL;
565 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000566 xmlChar *val;
567 const xmlChar *cur = value;
568 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000569 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000570
571 if (value == NULL) return(NULL);
572
573 q = cur;
574 while ((*cur != 0) && (cur - value < len)) {
575 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000576 /*
577 * Save the current text.
578 */
Daniel Veillard16253641998-10-28 22:58:05 +0000579 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000580 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
581 xmlNodeAddContentLen(last, q, cur - q);
582 } else {
583 node = xmlNewDocTextLen(doc, q, cur - q);
584 if (node == NULL) return(ret);
585 if (last == NULL)
586 last = ret = node;
587 else {
588 last->next = node;
589 node->prev = last;
590 last = node;
591 }
Daniel Veillard16253641998-10-28 22:58:05 +0000592 }
593 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000594 /*
595 * Read the entity string
596 */
Daniel Veillard16253641998-10-28 22:58:05 +0000597 cur++;
598 q = cur;
599 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
600 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000601#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +0000602 fprintf(stderr,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000603 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000604#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000605 return(ret);
606 }
607 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000608 /*
609 * Predefined entities don't generate nodes
610 */
Daniel Veillard16253641998-10-28 22:58:05 +0000611 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000612 ent = xmlGetDocEntity(doc, val);
613 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000614 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000615 if (last == NULL) {
616 node = xmlNewDocText(doc, ent->content);
617 last = ret = node;
618 } else
619 xmlNodeAddContent(last, ent->content);
620
621 } else {
622 /*
623 * Create a new REFERENCE_REF node
624 */
625 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000626 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000627 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000628 return(ret);
629 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000630 if (last == NULL)
631 last = ret = node;
632 else {
633 last->next = node;
634 node->prev = last;
635 last = node;
636 }
Daniel Veillard16253641998-10-28 22:58:05 +0000637 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000638 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000639 }
640 cur++;
641 q = cur;
642 } else
643 cur++;
644 }
645 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000646 /*
647 * Handle the last piece of text.
648 */
649 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
650 xmlNodeAddContentLen(last, q, cur - q);
651 } else {
652 node = xmlNewDocTextLen(doc, q, cur - q);
653 if (node == NULL) return(ret);
654 if (last == NULL)
655 last = ret = node;
656 else {
657 last->next = node;
658 node->prev = last;
659 last = node;
660 }
Daniel Veillard16253641998-10-28 22:58:05 +0000661 }
662 }
663 return(ret);
664}
665
666/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000667 * xmlStringGetNodeList:
668 * @doc: the document
669 * @value: the value of the attribute
670 *
671 * Parse the value string and build the node list associated. Should
672 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000673 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000674 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000675xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000676xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000677 xmlNodePtr ret = NULL, last = NULL;
678 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000679 xmlChar *val;
680 const xmlChar *cur = value;
681 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000682 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000683
684 if (value == NULL) return(NULL);
685
686 q = cur;
687 while (*cur != 0) {
688 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000689 /*
690 * Save the current text.
691 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000692 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000693 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
694 xmlNodeAddContentLen(last, q, cur - q);
695 } else {
696 node = xmlNewDocTextLen(doc, q, cur - q);
697 if (node == NULL) return(ret);
698 if (last == NULL)
699 last = ret = node;
700 else {
701 last->next = node;
702 node->prev = last;
703 last = node;
704 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000705 }
706 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000707 /*
708 * Read the entity string
709 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000710 cur++;
711 q = cur;
712 while ((*cur != 0) && (*cur != ';')) cur++;
713 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000714#ifdef DEBUG_TREE
Daniel Veillardccb09631998-10-27 06:21:04 +0000715 fprintf(stderr,
716 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000717#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000718 return(ret);
719 }
720 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000721 /*
722 * Predefined entities don't generate nodes
723 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000724 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000725 ent = xmlGetDocEntity(doc, val);
726 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000727 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000728 if (last == NULL) {
729 node = xmlNewDocText(doc, ent->content);
730 last = ret = node;
731 } else
732 xmlNodeAddContent(last, ent->content);
733
734 } else {
735 /*
736 * Create a new REFERENCE_REF node
737 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000738 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000739 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000740 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000741 return(ret);
742 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000743 if (last == NULL)
744 last = ret = node;
745 else {
746 last->next = node;
747 node->prev = last;
748 last = node;
749 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000750 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000751 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000752 }
753 cur++;
754 q = cur;
755 } else
756 cur++;
757 }
758 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000759 /*
760 * Handle the last piece of text.
761 */
762 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
763 xmlNodeAddContentLen(last, q, cur - q);
764 } else {
765 node = xmlNewDocTextLen(doc, q, cur - q);
766 if (node == NULL) return(ret);
767 if (last == NULL)
768 last = ret = node;
769 else {
770 last->next = node;
771 node->prev = last;
772 last = node;
773 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000774 }
775 }
776 return(ret);
777}
778
779/**
780 * xmlNodeListGetString:
781 * @doc: the document
782 * @list: a Node list
783 * @inLine: should we replace entity contents or show their external form
784 *
785 * Returns the string equivalent to the text contained in the Node list
786 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000787 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000788 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000789xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000790xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000791 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000792 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000793 xmlEntityPtr ent;
794
795 if (list == NULL) return(NULL);
796
797 while (node != NULL) {
Daniel Veillard87b95392000-08-12 21:12:04 +0000798 if ((node->type == XML_TEXT_NODE) ||
799 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000800 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000801#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000802 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000803#else
804 ret = xmlStrcat(ret, xmlBufferContent(node->content));
805#endif
806 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000807 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000808
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000809#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000810 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000811#else
812 buffer = xmlEncodeEntitiesReentrant(doc,
813 xmlBufferContent(node->content));
814#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000815 if (buffer != NULL) {
816 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000817 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000818 }
819 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000820 } else if (node->type == XML_ENTITY_REF_NODE) {
821 if (inLine) {
822 ent = xmlGetDocEntity(doc, node->name);
823 if (ent != NULL)
824 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000825 else {
826#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000827 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000828#else
829 ret = xmlStrcat(ret, xmlBufferContent(node->content));
830#endif
831 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000832 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000833 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000834 buf[0] = '&'; buf[1] = 0;
835 ret = xmlStrncat(ret, buf, 1);
836 ret = xmlStrcat(ret, node->name);
837 buf[0] = ';'; buf[1] = 0;
838 ret = xmlStrncat(ret, buf, 1);
839 }
840 }
841#if 0
842 else {
843 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
844 node->type);
845 }
846#endif
847 node = node->next;
848 }
849 return(ret);
850}
851
852/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000853 * xmlNodeListGetRawString:
854 * @doc: the document
855 * @list: a Node list
856 * @inLine: should we replace entity contents or show their external form
857 *
858 * Returns the string equivalent to the text contained in the Node list
859 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
860 * this function doesn't do any character encoding handling.
861 *
862 * Returns a pointer to the string copy, the calller must free it.
863 */
864xmlChar *
865xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
866 xmlNodePtr node = list;
867 xmlChar *ret = NULL;
868 xmlEntityPtr ent;
869
870 if (list == NULL) return(NULL);
871
872 while (node != NULL) {
873 if (node->type == XML_TEXT_NODE) {
874 if (inLine) {
875#ifndef XML_USE_BUFFER_CONTENT
876 ret = xmlStrcat(ret, node->content);
877#else
878 ret = xmlStrcat(ret, xmlBufferContent(node->content));
879#endif
880 } else {
881 xmlChar *buffer;
882
883#ifndef XML_USE_BUFFER_CONTENT
884 buffer = xmlEncodeSpecialChars(doc, node->content);
885#else
886 buffer = xmlEncodeSpecialChars(doc,
887 xmlBufferContent(node->content));
888#endif
889 if (buffer != NULL) {
890 ret = xmlStrcat(ret, buffer);
891 xmlFree(buffer);
892 }
893 }
894 } else if (node->type == XML_ENTITY_REF_NODE) {
895 if (inLine) {
896 ent = xmlGetDocEntity(doc, node->name);
897 if (ent != NULL)
898 ret = xmlStrcat(ret, ent->content);
899 else {
900#ifndef XML_USE_BUFFER_CONTENT
901 ret = xmlStrcat(ret, node->content);
902#else
903 ret = xmlStrcat(ret, xmlBufferContent(node->content));
904#endif
905 }
906 } else {
907 xmlChar buf[2];
908 buf[0] = '&'; buf[1] = 0;
909 ret = xmlStrncat(ret, buf, 1);
910 ret = xmlStrcat(ret, node->name);
911 buf[0] = ';'; buf[1] = 0;
912 ret = xmlStrncat(ret, buf, 1);
913 }
914 }
915#if 0
916 else {
917 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
918 node->type);
919 }
920#endif
921 node = node->next;
922 }
923 return(ret);
924}
925
926/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000927 * xmlNewProp:
928 * @node: the holding node
929 * @name: the name of the attribute
930 * @value: the value of the attribute
931 *
932 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000933 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000934 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000935xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000936xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000937 xmlAttrPtr cur;
938
939 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000940#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000941 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000942#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000943 return(NULL);
944 }
945
946 /*
947 * Allocate a new property and fill the fields.
948 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000949 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000950 if (cur == NULL) {
951 fprintf(stderr, "xmlNewProp : malloc failed\n");
952 return(NULL);
953 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000954 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000955 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000956
957 cur->parent = node;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000958 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000959 if (value != NULL) {
960 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000961 xmlNodePtr tmp;
962
Daniel Veillard51e3b151999-11-12 17:02:31 +0000963 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +0000964 cur->children = xmlStringGetNodeList(node->doc, buffer);
965 tmp = cur->children;
966 while (tmp != NULL) {
967 tmp->parent = (xmlNodePtr) cur;
968 if (tmp->next == NULL)
969 cur->last = tmp;
970 tmp = tmp->next;
971 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000972 xmlFree(buffer);
973 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000974
975 /*
976 * Add it at the end to preserve parsing order ...
977 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000978 if (node != NULL) {
979 if (node->properties == NULL) {
980 node->properties = cur;
981 } else {
982 xmlAttrPtr prev = node->properties;
983
984 while (prev->next != NULL) prev = prev->next;
985 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000986 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000987 }
988 }
989 return(cur);
990}
991
992/**
993 * xmlNewNsProp:
994 * @node: the holding node
995 * @ns: the namespace
996 * @name: the name of the attribute
997 * @value: the value of the attribute
998 *
999 * Create a new property tagged with a namespace and carried by a node.
1000 * Returns a pointer to the attribute
1001 */
1002xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001003xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1004 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001005 xmlAttrPtr cur;
1006
1007 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001008#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001009 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001010#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001011 return(NULL);
1012 }
1013
1014 /*
1015 * Allocate a new property and fill the fields.
1016 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001017 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001018 if (cur == NULL) {
1019 fprintf(stderr, "xmlNewProp : malloc failed\n");
1020 return(NULL);
1021 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001022 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001023 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001024
1025 cur->parent = node;
1026 if (node != NULL)
1027 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001028 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001029 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001030 if (value != NULL) {
1031 xmlChar *buffer;
1032 xmlNodePtr tmp;
1033
1034 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
1035 cur->children = xmlStringGetNodeList(node->doc, buffer);
1036 tmp = cur->children;
1037 while (tmp != NULL) {
1038 tmp->parent = (xmlNodePtr) cur;
1039 if (tmp->next == NULL)
1040 cur->last = tmp;
1041 tmp = tmp->next;
1042 }
1043 xmlFree(buffer);
1044 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001045
1046 /*
1047 * Add it at the end to preserve parsing order ...
1048 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001049 if (node != NULL) {
1050 if (node->properties == NULL) {
1051 node->properties = cur;
1052 } else {
1053 xmlAttrPtr prev = node->properties;
1054
1055 while (prev->next != NULL) prev = prev->next;
1056 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001057 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001058 }
1059 }
1060 return(cur);
1061}
1062
Daniel Veillard97b58771998-10-20 06:14:16 +00001063/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001064 * xmlNewDocProp:
1065 * @doc: the document
1066 * @name: the name of the attribute
1067 * @value: the value of the attribute
1068 *
1069 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001070 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001071 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001072xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001073xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001074 xmlAttrPtr cur;
1075
1076 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001077#ifdef DEBUG_TREE
Daniel Veillardccb09631998-10-27 06:21:04 +00001078 fprintf(stderr, "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001079#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001080 return(NULL);
1081 }
1082
1083 /*
1084 * Allocate a new property and fill the fields.
1085 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001086 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001087 if (cur == NULL) {
1088 fprintf(stderr, "xmlNewProp : malloc failed\n");
1089 return(NULL);
1090 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001091 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001092 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001093
Daniel Veillardcf461992000-03-14 18:30:20 +00001094 cur->name = xmlStrdup(name);
1095 cur->doc = doc;
1096 if (value != NULL)
1097 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillardccb09631998-10-27 06:21:04 +00001098 return(cur);
1099}
1100
1101/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001102 * xmlFreePropList:
1103 * @cur: the first property in the list
1104 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001105 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001106 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001107void
1108xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001109 xmlAttrPtr next;
1110 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001111#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001112 fprintf(stderr, "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001113#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001114 return;
1115 }
1116 while (cur != NULL) {
1117 next = cur->next;
1118 xmlFreeProp(cur);
1119 cur = next;
1120 }
1121}
1122
Daniel Veillard97b58771998-10-20 06:14:16 +00001123/**
1124 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001125 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001126 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001127 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001128 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001129void
1130xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001131 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001132#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001133 fprintf(stderr, "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001134#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001135 return;
1136 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001137 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001138 if ((cur->parent != NULL) &&
1139 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1140 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001141 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001142 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001143 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001144 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001145}
1146
Daniel Veillard97b58771998-10-20 06:14:16 +00001147/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001148 * xmlRemoveProp:
1149 * @cur: an attribute
1150 *
1151 * Unlink and free one attribute, all the content is freed too
1152 * Note this doesn't work for namespace definition attributes
1153 *
1154 * Returns 0 if success and -1 in case of error.
1155 */
1156int
1157xmlRemoveProp(xmlAttrPtr cur) {
1158 xmlAttrPtr tmp;
1159 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001160#ifdef DEBUG_TREE
Daniel Veillard686d6b62000-01-03 11:08:02 +00001161 fprintf(stderr, "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001162#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001163 return(-1);
1164 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001165 if (cur->parent == NULL) {
1166#ifdef DEBUG_TREE
1167 fprintf(stderr, "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001168#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001169 return(-1);
1170 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001171 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001172 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001173 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001174 xmlFreeProp(cur);
1175 return(0);
1176 }
1177 while (tmp != NULL) {
1178 if (tmp->next == cur) {
1179 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001180 if (tmp->next != NULL)
1181 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001182 xmlFreeProp(cur);
1183 return(0);
1184 }
1185 tmp = tmp->next;
1186 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001187#ifdef DEBUG_TREE
Daniel Veillard686d6b62000-01-03 11:08:02 +00001188 fprintf(stderr, "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001189#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001190 return(-1);
1191}
1192
1193/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001194 * xmlNewPI:
1195 * @name: the processing instruction name
1196 * @content: the PI content
1197 *
1198 * Creation of a processing instruction element.
1199 * Returns a pointer to the new node object.
1200 */
1201xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001202xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001203 xmlNodePtr cur;
1204
1205 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001206#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001207 fprintf(stderr, "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001208#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001209 return(NULL);
1210 }
1211
1212 /*
1213 * Allocate a new node and fill the fields.
1214 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001215 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001216 if (cur == NULL) {
1217 fprintf(stderr, "xmlNewPI : malloc failed\n");
1218 return(NULL);
1219 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001220 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001221 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001222
Daniel Veillardb96e6431999-08-29 21:02:19 +00001223 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001224 if (content != NULL) {
1225#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001226 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001227#else
1228 cur->content = xmlBufferCreateSize(0);
1229 xmlBufferSetAllocationScheme(cur->content,
1230 xmlGetBufferAllocationScheme());
1231 xmlBufferAdd(cur->content, content, -1);
1232#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001233 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001234 return(cur);
1235}
1236
1237/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001238 * xmlNewNode:
1239 * @ns: namespace if any
1240 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001241 *
Daniel Veillarde0854c32000-08-27 21:12:29 +00001242 * Creation of a new node element. @ns is optionnal (NULL).
1243 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001244 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001245 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001246xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001247xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001248 xmlNodePtr cur;
1249
1250 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001251#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001252 fprintf(stderr, "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001253#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001254 return(NULL);
1255 }
1256
1257 /*
1258 * Allocate a new node and fill the fields.
1259 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001260 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001261 if (cur == NULL) {
1262 fprintf(stderr, "xmlNewNode : malloc failed\n");
1263 return(NULL);
1264 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001265 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001266 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001267
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268 cur->name = xmlStrdup(name);
1269 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001270 return(cur);
1271}
1272
Daniel Veillard97b58771998-10-20 06:14:16 +00001273/**
1274 * xmlNewDocNode:
1275 * @doc: the document
1276 * @ns: namespace if any
1277 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001278 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001279 *
1280 * Creation of a new node element within a document. @ns and @content
1281 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001282 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1283 * references, but XML special chars need to be escaped first by using
1284 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1285 * need entities support.
1286 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001287 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001288 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001289xmlNodePtr
1290xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001291 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001292 xmlNodePtr cur;
1293
Daniel Veillardccb09631998-10-27 06:21:04 +00001294 cur = xmlNewNode(ns, name);
1295 if (cur != NULL) {
1296 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001297 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001298 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001299 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001300 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001301 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001302 return(cur);
1303}
1304
1305
Daniel Veillard97b58771998-10-20 06:14:16 +00001306/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001307 * xmlNewDocRawNode:
1308 * @doc: the document
1309 * @ns: namespace if any
1310 * @name: the node name
1311 * @content: the text content if any
1312 *
1313 * Creation of a new node element within a document. @ns and @content
1314 * are optionnal (NULL).
1315 *
1316 * Returns a pointer to the new node object.
1317 */
1318xmlNodePtr
1319xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1320 const xmlChar *name, const xmlChar *content) {
1321 xmlNodePtr cur;
1322
1323 cur = xmlNewNode(ns, name);
1324 if (cur != NULL) {
1325 cur->doc = doc;
1326 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001327 cur->children = xmlNewDocText(doc, content);
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001328 UPDATE_LAST_CHILD(cur)
1329 }
1330 }
1331 return(cur);
1332}
1333
Daniel Veillard2eac5032000-01-09 21:08:56 +00001334/**
1335 * xmlNewDocFragment:
1336 * @doc: the document owning the fragment
1337 *
1338 * Creation of a new Fragment node.
1339 * Returns a pointer to the new node object.
1340 */
1341xmlNodePtr
1342xmlNewDocFragment(xmlDocPtr doc) {
1343 xmlNodePtr cur;
1344
1345 /*
1346 * Allocate a new DocumentFragment node and fill the fields.
1347 */
1348 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1349 if (cur == NULL) {
1350 fprintf(stderr, "xmlNewDocFragment : malloc failed\n");
1351 return(NULL);
1352 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001353 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001354 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001355
Daniel Veillard2eac5032000-01-09 21:08:56 +00001356 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001357 return(cur);
1358}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001359
1360/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001361 * xmlNewText:
1362 * @content: the text content
1363 *
1364 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001365 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001366 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001367xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001368xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001369 xmlNodePtr cur;
1370
1371 /*
1372 * Allocate a new node and fill the fields.
1373 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001374 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001375 if (cur == NULL) {
1376 fprintf(stderr, "xmlNewText : malloc failed\n");
1377 return(NULL);
1378 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001379 memset(cur, 0, sizeof(xmlNode));
1380 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001381
Daniel Veillard260a68f1998-08-13 03:39:55 +00001382 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001383 if (content != NULL) {
1384#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001385 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001386#else
1387 cur->content = xmlBufferCreateSize(0);
1388 xmlBufferSetAllocationScheme(cur->content,
1389 xmlGetBufferAllocationScheme());
1390 xmlBufferAdd(cur->content, content, -1);
1391#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001392 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001393 return(cur);
1394}
1395
Daniel Veillard97b58771998-10-20 06:14:16 +00001396/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001397 * xmlNewTextChild:
1398 * @parent: the parent node
1399 * @ns: a namespace if any
1400 * @name: the name of the child
1401 * @content: the text content of the child if any.
1402 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001403 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001404 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1405 * a child TEXT node will be created containing the string content.
1406 *
1407 * Returns a pointer to the new node object.
1408 */
1409xmlNodePtr
1410xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1411 const xmlChar *name, const xmlChar *content) {
1412 xmlNodePtr cur, prev;
1413
1414 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001415#ifdef DEBUG_TREE
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001416 fprintf(stderr, "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001417#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001418 return(NULL);
1419 }
1420
1421 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001422#ifdef DEBUG_TREE
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001423 fprintf(stderr, "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001424#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001425 return(NULL);
1426 }
1427
1428 /*
1429 * Allocate a new node
1430 */
1431 if (ns == NULL)
1432 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1433 else
1434 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1435 if (cur == NULL) return(NULL);
1436
1437 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001438 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001439 */
1440 cur->type = XML_ELEMENT_NODE;
1441 cur->parent = parent;
1442 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001443 if (parent->children == NULL) {
1444 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001445 parent->last = cur;
1446 } else {
1447 prev = parent->last;
1448 prev->next = cur;
1449 cur->prev = prev;
1450 parent->last = cur;
1451 }
1452
1453 return(cur);
1454}
1455
1456/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001457 * xmlNewCharRef:
1458 * @doc: the document
1459 * @name: the char ref string, starting with # or "&# ... ;"
1460 *
1461 * Creation of a new character reference node.
1462 * Returns a pointer to the new node object.
1463 */
1464xmlNodePtr
1465xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1466 xmlNodePtr cur;
1467
1468 /*
1469 * Allocate a new node and fill the fields.
1470 */
1471 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1472 if (cur == NULL) {
1473 fprintf(stderr, "xmlNewText : malloc failed\n");
1474 return(NULL);
1475 }
1476 memset(cur, 0, sizeof(xmlNode));
1477 cur->type = XML_ENTITY_REF_NODE;
1478
1479 cur->doc = doc;
1480 if (name[0] == '&') {
1481 int len;
1482 name++;
1483 len = xmlStrlen(name);
1484 if (name[len - 1] == ';')
1485 cur->name = xmlStrndup(name, len - 1);
1486 else
1487 cur->name = xmlStrndup(name, len);
1488 } else
1489 cur->name = xmlStrdup(name);
1490 return(cur);
1491}
1492
1493/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001494 * xmlNewReference:
1495 * @doc: the document
1496 * @name: the reference name, or the reference string with & and ;
1497 *
1498 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001499 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001500 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001501xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001502xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001503 xmlNodePtr cur;
1504 xmlEntityPtr ent;
1505
1506 /*
1507 * Allocate a new node and fill the fields.
1508 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001509 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001510 if (cur == NULL) {
1511 fprintf(stderr, "xmlNewText : malloc failed\n");
1512 return(NULL);
1513 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001514 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001515 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001516
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001517 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001518 if (name[0] == '&') {
1519 int len;
1520 name++;
1521 len = xmlStrlen(name);
1522 if (name[len - 1] == ';')
1523 cur->name = xmlStrndup(name, len - 1);
1524 else
1525 cur->name = xmlStrndup(name, len);
1526 } else
1527 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001528
1529 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001530 if (ent != NULL) {
1531#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001532 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001533#else
1534 /*
1535 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1536 * a copy of this pointer. Let's hope we don't manipulate it
1537 * later
1538 */
1539 cur->content = xmlBufferCreateSize(0);
1540 xmlBufferSetAllocationScheme(cur->content,
1541 xmlGetBufferAllocationScheme());
1542 if (ent->content != NULL)
1543 xmlBufferAdd(cur->content, ent->content, -1);
1544#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001545 cur->children = (xmlNodePtr) ent;
1546 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001547 return(cur);
1548}
1549
1550/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001551 * xmlNewDocText:
1552 * @doc: the document
1553 * @content: the text content
1554 *
1555 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001556 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001557 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001558xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001559xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001560 xmlNodePtr cur;
1561
1562 cur = xmlNewText(content);
1563 if (cur != NULL) cur->doc = doc;
1564 return(cur);
1565}
1566
Daniel Veillard97b58771998-10-20 06:14:16 +00001567/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001568 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001569 * @content: the text content
1570 * @len: the text len.
1571 *
1572 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001573 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001574 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001575xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001576xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001577 xmlNodePtr cur;
1578
1579 /*
1580 * Allocate a new node and fill the fields.
1581 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001582 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001583 if (cur == NULL) {
1584 fprintf(stderr, "xmlNewText : malloc failed\n");
1585 return(NULL);
1586 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001587 memset(cur, 0, sizeof(xmlNode));
1588 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001589
Daniel Veillard260a68f1998-08-13 03:39:55 +00001590 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001591 if (content != NULL) {
1592#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001593 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001594#else
1595 cur->content = xmlBufferCreateSize(len);
1596 xmlBufferSetAllocationScheme(cur->content,
1597 xmlGetBufferAllocationScheme());
1598 xmlBufferAdd(cur->content, content, len);
1599#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001600 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001601 return(cur);
1602}
1603
Daniel Veillard97b58771998-10-20 06:14:16 +00001604/**
1605 * xmlNewDocTextLen:
1606 * @doc: the document
1607 * @content: the text content
1608 * @len: the text len.
1609 *
1610 * Creation of a new text node with an extra content lenght parameter. The
1611 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001612 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001613 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001614xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001615xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001616 xmlNodePtr cur;
1617
1618 cur = xmlNewTextLen(content, len);
1619 if (cur != NULL) cur->doc = doc;
1620 return(cur);
1621}
1622
Daniel Veillard97b58771998-10-20 06:14:16 +00001623/**
1624 * xmlNewComment:
1625 * @content: the comment content
1626 *
1627 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001628 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001629 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001630xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001631xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001632 xmlNodePtr cur;
1633
1634 /*
1635 * Allocate a new node and fill the fields.
1636 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001637 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001638 if (cur == NULL) {
1639 fprintf(stderr, "xmlNewComment : malloc failed\n");
1640 return(NULL);
1641 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001642 memset(cur, 0, sizeof(xmlNode));
1643 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001644
Daniel Veillardcf461992000-03-14 18:30:20 +00001645 cur->name = xmlStrdup(xmlStringComment);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001646 if (content != NULL) {
1647#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001648 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001649#else
1650 cur->content = xmlBufferCreateSize(0);
1651 xmlBufferSetAllocationScheme(cur->content,
1652 xmlGetBufferAllocationScheme());
1653 xmlBufferAdd(cur->content, content, -1);
1654#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001655 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001656 return(cur);
1657}
1658
Daniel Veillard97b58771998-10-20 06:14:16 +00001659/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001660 * xmlNewCDataBlock:
1661 * @doc: the document
1662 * @content: the CData block content content
1663 * @len: the length of the block
1664 *
1665 * Creation of a new node containing a CData block.
1666 * Returns a pointer to the new node object.
1667 */
1668xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001669xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001670 xmlNodePtr cur;
1671
1672 /*
1673 * Allocate a new node and fill the fields.
1674 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001675 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001676 if (cur == NULL) {
1677 fprintf(stderr, "xmlNewCDataBlock : malloc failed\n");
1678 return(NULL);
1679 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001680 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001681 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001682
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001683 if (content != NULL) {
1684#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001685 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001686#else
1687 cur->content = xmlBufferCreateSize(len);
1688 xmlBufferSetAllocationScheme(cur->content,
1689 xmlGetBufferAllocationScheme());
1690 xmlBufferAdd(cur->content, content, len);
1691#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001692 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001693 return(cur);
1694}
1695
1696/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001697 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001698 * @doc: the document
1699 * @content: the comment content
1700 *
1701 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001702 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001703 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001704xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001705xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001706 xmlNodePtr cur;
1707
1708 cur = xmlNewComment(content);
1709 if (cur != NULL) cur->doc = doc;
1710 return(cur);
1711}
1712
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001713
Daniel Veillard97b58771998-10-20 06:14:16 +00001714/**
1715 * xmlNewChild:
1716 * @parent: the parent node
1717 * @ns: a namespace if any
1718 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001719 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001720 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001721 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001722 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1723 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001724 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1725 * references, but XML special chars need to be escaped first by using
1726 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1727 * support is not needed.
1728 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001729 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001730 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001731xmlNodePtr
1732xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001733 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001734 xmlNodePtr cur, prev;
1735
1736 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001737#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001738 fprintf(stderr, "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001739#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001740 return(NULL);
1741 }
1742
1743 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001744#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00001745 fprintf(stderr, "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001746#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001747 return(NULL);
1748 }
1749
1750 /*
1751 * Allocate a new node
1752 */
1753 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001754 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001755 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001756 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001757 if (cur == NULL) return(NULL);
1758
1759 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001760 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001761 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001762 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001763 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001764 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001765 if (parent->children == NULL) {
1766 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001767 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001768 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001769 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001770 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001771 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001772 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001773 }
1774
1775 return(cur);
1776}
1777
Daniel Veillard97b58771998-10-20 06:14:16 +00001778/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001779 * xmlAddNextSibling:
1780 * @cur: the child node
1781 * @elem: the new node
1782 *
1783 * Add a new element @elem as the next siblings of @cur
1784 * If the new element was already inserted in a document it is
1785 * first unlinked from its existing context.
1786 *
1787 * Returns the new element or NULL in case of error.
1788 */
1789xmlNodePtr
1790xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1791 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001792#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001793 fprintf(stderr, "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001794#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001795 return(NULL);
1796 }
1797 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001798#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001799 fprintf(stderr, "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001800#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001801 return(NULL);
1802 }
1803
1804 xmlUnlinkNode(elem);
1805 elem->doc = cur->doc;
1806 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001807 elem->prev = cur;
1808 elem->next = cur->next;
1809 cur->next = elem;
1810 if (elem->next != NULL)
1811 elem->next->prev = elem;
1812 if ((elem->parent != NULL) && (elem->parent->last == cur))
1813 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001814 return(elem);
1815}
1816
1817/**
1818 * xmlAddPrevSibling:
1819 * @cur: the child node
1820 * @elem: the new node
1821 *
1822 * Add a new element @elem as the previous siblings of @cur
1823 * If the new element was already inserted in a document it is
1824 * first unlinked from its existing context.
1825 *
1826 * Returns the new element or NULL in case of error.
1827 */
1828xmlNodePtr
1829xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1830 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001831#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001832 fprintf(stderr, "xmlAddPrevSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001833#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001834 return(NULL);
1835 }
1836 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001837#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001838 fprintf(stderr, "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001839#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001840 return(NULL);
1841 }
1842
1843 xmlUnlinkNode(elem);
1844 elem->doc = cur->doc;
1845 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001846 elem->next = cur;
1847 elem->prev = cur->prev;
1848 cur->prev = elem;
1849 if (elem->prev != NULL)
1850 elem->prev->next = elem;
1851 if ((elem->parent != NULL) && (elem->parent->children == cur))
1852 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001853 return(elem);
1854}
1855
1856/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001857 * xmlAddSibling:
1858 * @cur: the child node
1859 * @elem: the new node
1860 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001861 * Add a new element @elem to the list of siblings of @cur
1862 * If the new element was already inserted in a document it is
1863 * first unlinked from its existing context.
1864 *
1865 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001866 */
1867xmlNodePtr
1868xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1869 xmlNodePtr parent;
1870
1871 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001872#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001873 fprintf(stderr, "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001874#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001875 return(NULL);
1876 }
1877
1878 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001879#ifdef DEBUG_TREE
Daniel Veillardb96e6431999-08-29 21:02:19 +00001880 fprintf(stderr, "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001881#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001882 return(NULL);
1883 }
1884
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001885 /*
1886 * Constant time is we can rely on the ->parent->last to find
1887 * the last sibling.
1888 */
1889 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001890 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001891 (cur->parent->last != NULL) &&
1892 (cur->parent->last->next == NULL)) {
1893 cur = cur->parent->last;
1894 } else {
1895 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001896 }
1897
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001898 xmlUnlinkNode(elem);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001899 if (elem->doc == NULL)
1900 elem->doc = cur->doc; /* the parent may not be linked to a doc ! */
1901
1902 parent = cur->parent;
1903 elem->prev = cur;
1904 elem->next = NULL;
1905 elem->parent = parent;
1906 cur->next = elem;
1907 if (parent != NULL)
1908 parent->last = elem;
1909
1910 return(elem);
1911}
1912
1913/**
Daniel Veillard87b95392000-08-12 21:12:04 +00001914 * xmlAddChildList:
1915 * @parent: the parent node
1916 * @cur: the first node in the list
1917 *
1918 * Add a list of node at the end of the child list of the parent
1919 *
1920 * Returns the last child or NULL in case of error.
1921 */
1922xmlNodePtr
1923xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
1924 xmlNodePtr prev;
1925
1926 if (parent == NULL) {
1927#ifdef DEBUG_TREE
1928 fprintf(stderr, "xmlAddChild : parent == NULL\n");
1929#endif
1930 return(NULL);
1931 }
1932
1933 if (cur == NULL) {
1934#ifdef DEBUG_TREE
1935 fprintf(stderr, "xmlAddChild : child == NULL\n");
1936#endif
1937 return(NULL);
1938 }
1939
1940 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1941 (cur->doc != parent->doc)) {
1942#ifdef DEBUG_TREE
1943 fprintf(stderr, "Elements moved to a different document\n");
1944#endif
1945 }
1946
1947 /*
1948 * add the first element at the end of the children list.
1949 */
1950 if (parent->children == NULL) {
1951 parent->children = cur;
1952 } else {
1953 prev = parent->last;
1954 prev->next = cur;
1955 cur->prev = prev;
1956 }
1957 while (cur->next != NULL) {
1958 cur->parent = parent;
1959 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
1960 cur = cur->next;
1961 }
1962 cur->parent = parent;
1963 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
1964 parent->last = cur;
1965
1966 return(cur);
1967}
1968
1969/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001970 * xmlAddChild:
1971 * @parent: the parent node
1972 * @cur: the child node
1973 *
1974 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001975 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001976 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001977xmlNodePtr
1978xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001979 xmlNodePtr prev;
1980
1981 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001982#ifdef DEBUG_TREE
Daniel Veillard10a2c651999-12-12 13:03:50 +00001983 fprintf(stderr, "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001984#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001985 return(NULL);
1986 }
1987
1988 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001989#ifdef DEBUG_TREE
Daniel Veillard10a2c651999-12-12 13:03:50 +00001990 fprintf(stderr, "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001991#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001992 return(NULL);
1993 }
1994
Daniel Veillard0bef1311998-10-14 02:36:47 +00001995 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1996 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001997#ifdef DEBUG_TREE
Daniel Veillard0bef1311998-10-14 02:36:47 +00001998 fprintf(stderr, "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001999#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002000 }
2001
Daniel Veillard260a68f1998-08-13 03:39:55 +00002002 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002003 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002004 */
2005 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002006 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002007
Daniel Veillardccb09631998-10-27 06:21:04 +00002008 /*
2009 * Handle the case where parent->content != NULL, in that case it will
2010 * create a intermediate TEXT node.
2011 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002012 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2013 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002014 xmlNodePtr text;
2015
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002016#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002017 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002018#else
2019 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2020#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002021 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002022 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002023 if (text->next != NULL)
2024 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002025 parent->children = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002026 UPDATE_LAST_CHILD(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002027#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002028 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002029#else
2030 xmlBufferFree(parent->content);
2031#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002032 parent->content = NULL;
2033 }
2034 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002035 if (parent->children == NULL) {
2036 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002037 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002038 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002039 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002040 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002041 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002042 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002043 }
2044
2045 return(cur);
2046}
2047
Daniel Veillard97b58771998-10-20 06:14:16 +00002048/**
2049 * xmlGetLastChild:
2050 * @parent: the parent node
2051 *
2052 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002053 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002054 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002055xmlNodePtr
2056xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002057 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002058#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002059 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002060#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002061 return(NULL);
2062 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002063 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002064}
2065
Daniel Veillard97b58771998-10-20 06:14:16 +00002066/**
2067 * xmlFreeNodeList:
2068 * @cur: the first node in the list
2069 *
2070 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002071 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002072 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002073void
2074xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002075 xmlNodePtr next;
2076 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002077#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002078 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002079#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002080 return;
2081 }
2082 while (cur != NULL) {
2083 next = cur->next;
2084 xmlFreeNode(cur);
2085 cur = next;
2086 }
2087}
2088
Daniel Veillard97b58771998-10-20 06:14:16 +00002089/**
2090 * xmlFreeNode:
2091 * @cur: the node
2092 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002093 * Free a node, this is a recursive behaviour, all the children are freed too.
2094 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002095 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002096void
2097xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002098 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002099#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002100 fprintf(stderr, "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002101#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002102 return;
2103 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002104 if (cur->type == XML_DTD_NODE)
2105 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002106 cur->doc = NULL;
2107 cur->parent = NULL;
2108 cur->next = NULL;
2109 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002110 if ((cur->children != NULL) &&
2111 (cur->type != XML_ENTITY_REF_NODE))
2112 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002113 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2114 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002115#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002116 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002117#else
2118 if (cur->content != NULL) xmlBufferFree(cur->content);
2119#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00002120 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002121 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2122 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002123 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002124}
2125
Daniel Veillard16253641998-10-28 22:58:05 +00002126/**
2127 * xmlUnlinkNode:
2128 * @cur: the node
2129 *
2130 * Unlink a node from it's current context, the node is not freed
2131 */
2132void
2133xmlUnlinkNode(xmlNodePtr cur) {
2134 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002135#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00002136 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002137#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002138 return;
2139 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002140 if ((cur->parent != NULL) && (cur->parent->children == cur))
2141 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002142 if ((cur->parent != NULL) && (cur->parent->last == cur))
2143 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002144 if (cur->next != NULL)
2145 cur->next->prev = cur->prev;
2146 if (cur->prev != NULL)
2147 cur->prev->next = cur->next;
2148 cur->next = cur->prev = NULL;
2149 cur->parent = NULL;
2150}
2151
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002152/**
2153 * xmlReplaceNode:
2154 * @old: the old node
2155 * @cur: the node
2156 *
2157 * Unlink the old node from it's current context, prune the new one
2158 * at the same place. If cur was already inserted in a document it is
2159 * first unlinked from its existing context.
2160 *
2161 * Returns the old node
2162 */
2163xmlNodePtr
2164xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2165 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002166#ifdef DEBUG_TREE
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002167 fprintf(stderr, "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002168#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002169 return(NULL);
2170 }
2171 if (cur == NULL) {
2172 xmlUnlinkNode(old);
2173 return(old);
2174 }
2175 xmlUnlinkNode(cur);
2176 cur->doc = old->doc;
2177 cur->parent = old->parent;
2178 cur->next = old->next;
2179 if (cur->next != NULL)
2180 cur->next->prev = cur;
2181 cur->prev = old->prev;
2182 if (cur->prev != NULL)
2183 cur->prev->next = cur;
2184 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002185 if (cur->parent->children == old)
2186 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002187 if (cur->parent->last == old)
2188 cur->parent->last = cur;
2189 }
2190 old->next = old->prev = NULL;
2191 old->parent = NULL;
2192 return(old);
2193}
2194
Daniel Veillard260a68f1998-08-13 03:39:55 +00002195/************************************************************************
2196 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002197 * Copy operations *
2198 * *
2199 ************************************************************************/
2200
2201/**
2202 * xmlCopyNamespace:
2203 * @cur: the namespace
2204 *
2205 * Do a copy of the namespace.
2206 *
2207 * Returns: a new xmlNsPtr, or NULL in case of error.
2208 */
2209xmlNsPtr
2210xmlCopyNamespace(xmlNsPtr cur) {
2211 xmlNsPtr ret;
2212
2213 if (cur == NULL) return(NULL);
2214 switch (cur->type) {
2215 case XML_GLOBAL_NAMESPACE:
2216 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
2217 break;
2218 case XML_LOCAL_NAMESPACE:
2219 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2220 break;
2221 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002222#ifdef DEBUG_TREE
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002223 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002224#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002225 return(NULL);
2226 }
2227 return(ret);
2228}
2229
2230/**
2231 * xmlCopyNamespaceList:
2232 * @cur: the first namespace
2233 *
2234 * Do a copy of an namespace list.
2235 *
2236 * Returns: a new xmlNsPtr, or NULL in case of error.
2237 */
2238xmlNsPtr
2239xmlCopyNamespaceList(xmlNsPtr cur) {
2240 xmlNsPtr ret = NULL;
2241 xmlNsPtr p = NULL,q;
2242
2243 while (cur != NULL) {
2244 q = xmlCopyNamespace(cur);
2245 if (p == NULL) {
2246 ret = p = q;
2247 } else {
2248 p->next = q;
2249 p = q;
2250 }
2251 cur = cur->next;
2252 }
2253 return(ret);
2254}
2255
2256/**
2257 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002258 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002259 * @cur: the attribute
2260 *
2261 * Do a copy of the attribute.
2262 *
2263 * Returns: a new xmlAttrPtr, or NULL in case of error.
2264 */
2265xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002266xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002267 xmlAttrPtr ret;
2268
2269 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002270 if (cur->parent != NULL)
2271 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2272 else if (cur->children != NULL)
2273 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002274 else
2275 ret = xmlNewDocProp(NULL, cur->name, NULL);
2276 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002277 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002278
2279 if ((cur->ns != NULL) && (target != NULL)) {
2280 xmlNsPtr ns;
2281
2282 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2283 ret->ns = ns;
2284 } else
2285 ret->ns = NULL;
2286
Daniel Veillardcf461992000-03-14 18:30:20 +00002287 if (cur->children != NULL)
2288 ret->children = xmlCopyNodeList(cur->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002289 return(ret);
2290}
2291
2292/**
2293 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002294 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002295 * @cur: the first attribute
2296 *
2297 * Do a copy of an attribute list.
2298 *
2299 * Returns: a new xmlAttrPtr, or NULL in case of error.
2300 */
2301xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002302xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002303 xmlAttrPtr ret = NULL;
2304 xmlAttrPtr p = NULL,q;
2305
2306 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002307 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002308 if (p == NULL) {
2309 ret = p = q;
2310 } else {
2311 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002312 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002313 p = q;
2314 }
2315 cur = cur->next;
2316 }
2317 return(ret);
2318}
2319
2320/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002321 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002322 *
2323 * They are splitted into external and internal parts for one
2324 * tricky reason: namespaces. Doing a direct copy of a node
2325 * say RPM:Copyright without changing the namespace pointer to
2326 * something else can produce stale links. One way to do it is
2327 * to keep a reference counter but this doesn't work as soon
2328 * as one move the element or the subtree out of the scope of
2329 * the existing namespace. The actual solution seems to add
2330 * a copy of the namespace at the top of the copied tree if
2331 * not available in the subtree.
2332 * Hence two functions, the public front-end call the inner ones
2333 */
2334
2335static xmlNodePtr
2336xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2337
2338static xmlNodePtr
2339xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2340 int recursive) {
2341 xmlNodePtr ret;
2342
2343 if (node == NULL) return(NULL);
2344 /*
2345 * Allocate a new node and fill the fields.
2346 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002347 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002348 if (ret == NULL) {
2349 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
2350 return(NULL);
2351 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002352 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002353 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002354
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002355 ret->doc = doc;
2356 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002357 if (node->name != NULL)
2358 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002359 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2360#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002361 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002362#else
2363 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2364 xmlBufferSetAllocationScheme(ret->content,
2365 xmlGetBufferAllocationScheme());
2366 xmlBufferAdd(ret->content,
2367 xmlBufferContent(node->content),
2368 xmlBufferLength(node->content));
2369#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002370 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002371 if (parent != NULL)
2372 xmlAddChild(parent, ret);
2373
2374 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002375 if (node->nsDef != NULL)
2376 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2377
2378 if (node->ns != NULL) {
2379 xmlNsPtr ns;
2380
2381 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2382 if (ns == NULL) {
2383 /*
2384 * Humm, we are copying an element whose namespace is defined
2385 * out of the new tree scope. Search it in the original tree
2386 * and add it at the top of the new tree
2387 */
2388 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2389 if (ns != NULL) {
2390 xmlNodePtr root = ret;
2391
2392 while (root->parent != NULL) root = root->parent;
2393 xmlNewNs(root, ns->href, ns->prefix);
2394 }
2395 } else {
2396 /*
2397 * reference the existing namespace definition in our own tree.
2398 */
2399 ret->ns = ns;
2400 }
2401 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002402 if (node->properties != NULL)
2403 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002404 if (node->children != NULL)
2405 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002406 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002407 return(ret);
2408}
2409
2410static xmlNodePtr
2411xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2412 xmlNodePtr ret = NULL;
2413 xmlNodePtr p = NULL,q;
2414
2415 while (node != NULL) {
2416 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002417 if (ret == NULL) {
2418 q->prev = NULL;
2419 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002420 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002421 p->next = q;
2422 q->prev = p;
2423 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002424 }
2425 node = node->next;
2426 }
2427 return(ret);
2428}
2429
2430/**
2431 * xmlCopyNode:
2432 * @node: the node
2433 * @recursive: if 1 do a recursive copy.
2434 *
2435 * Do a copy of the node.
2436 *
2437 * Returns: a new xmlNodePtr, or NULL in case of error.
2438 */
2439xmlNodePtr
2440xmlCopyNode(xmlNodePtr node, int recursive) {
2441 xmlNodePtr ret;
2442
2443 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2444 return(ret);
2445}
2446
2447/**
2448 * xmlCopyNodeList:
2449 * @node: the first node in the list.
2450 *
2451 * Do a recursive copy of the node list.
2452 *
2453 * Returns: a new xmlNodePtr, or NULL in case of error.
2454 */
2455xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2456 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2457 return(ret);
2458}
2459
2460/**
2461 * xmlCopyElement:
2462 * @elem: the element
2463 *
2464 * Do a copy of the element definition.
2465 *
2466 * Returns: a new xmlElementPtr, or NULL in case of error.
2467xmlElementPtr
2468xmlCopyElement(xmlElementPtr elem) {
2469 xmlElementPtr ret;
2470
2471 if (elem == NULL) return(NULL);
2472 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2473 if (ret == NULL) return(NULL);
2474 if (!recursive) return(ret);
2475 if (elem->properties != NULL)
2476 ret->properties = xmlCopyPropList(elem->properties);
2477
2478 if (elem->nsDef != NULL)
2479 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002480 if (elem->children != NULL)
2481 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002482 return(ret);
2483}
2484 */
2485
2486/**
2487 * xmlCopyDtd:
2488 * @dtd: the dtd
2489 *
2490 * Do a copy of the dtd.
2491 *
2492 * Returns: a new xmlDtdPtr, or NULL in case of error.
2493 */
2494xmlDtdPtr
2495xmlCopyDtd(xmlDtdPtr dtd) {
2496 xmlDtdPtr ret;
2497
2498 if (dtd == NULL) return(NULL);
2499 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2500 if (ret == NULL) return(NULL);
2501 if (dtd->entities != NULL)
2502 ret->entities = (void *) xmlCopyEntitiesTable(
2503 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002504 if (dtd->notations != NULL)
2505 ret->notations = (void *) xmlCopyNotationTable(
2506 (xmlNotationTablePtr) dtd->notations);
2507 if (dtd->elements != NULL)
2508 ret->elements = (void *) xmlCopyElementTable(
2509 (xmlElementTablePtr) dtd->elements);
2510 if (dtd->attributes != NULL)
2511 ret->attributes = (void *) xmlCopyAttributeTable(
2512 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002513 return(ret);
2514}
2515
2516/**
2517 * xmlCopyDoc:
2518 * @doc: the document
2519 * @recursive: if 1 do a recursive copy.
2520 *
2521 * Do a copy of the document info. If recursive, the content tree will
2522 * be copied too as well as Dtd, namespaces and entities.
2523 *
2524 * Returns: a new xmlDocPtr, or NULL in case of error.
2525 */
2526xmlDocPtr
2527xmlCopyDoc(xmlDocPtr doc, int recursive) {
2528 xmlDocPtr ret;
2529
2530 if (doc == NULL) return(NULL);
2531 ret = xmlNewDoc(doc->version);
2532 if (ret == NULL) return(NULL);
2533 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002534 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002535 if (doc->encoding != NULL)
2536 ret->encoding = xmlStrdup(doc->encoding);
2537 ret->compression = doc->compression;
2538 ret->standalone = doc->standalone;
2539 if (!recursive) return(ret);
2540
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002541 if (doc->intSubset != NULL)
2542 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002543 if (doc->oldNs != NULL)
2544 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillardcf461992000-03-14 18:30:20 +00002545 if (doc->children != NULL)
Daniel Veillard06047432000-04-24 11:33:38 +00002546 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2547 (xmlNodePtr)ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002548 return(ret);
2549}
2550
2551/************************************************************************
2552 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002553 * Content access functions *
2554 * *
2555 ************************************************************************/
2556
Daniel Veillard97b58771998-10-20 06:14:16 +00002557/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002558 * xmlDocGetRootElement:
2559 * @doc: the document
2560 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002561 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002562 * containing possibly comments, PIs, etc ...).
2563 *
2564 * Returns the xmlNodePtr for the root or NULL
2565 */
2566xmlNodePtr
2567xmlDocGetRootElement(xmlDocPtr doc) {
2568 xmlNodePtr ret;
2569
2570 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002571 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002572 while (ret != NULL) {
2573 if (ret->type == XML_ELEMENT_NODE)
2574 return(ret);
2575 ret = ret->next;
2576 }
2577 return(ret);
2578}
2579
2580/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002581 * xmlDocSetRootElement:
2582 * @doc: the document
2583 * @root: the new document root element
2584 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002585 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002586 * containing possibly comments, PIs, etc ...).
2587 *
2588 * Returns the old root element if any was found
2589 */
2590xmlNodePtr
2591xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2592 xmlNodePtr old = NULL;
2593
2594 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002595 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002596 while (old != NULL) {
2597 if (old->type == XML_ELEMENT_NODE)
2598 break;
2599 old = old->next;
2600 }
2601 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002602 if (doc->children == NULL) {
2603 doc->children = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002604 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002605 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002606 }
2607 } else {
2608 xmlReplaceNode(old, root);
2609 }
2610 return(old);
2611}
2612
2613/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002614 * xmlNodeSetLang:
2615 * @cur: the node being changed
2616 * @lang: the langage description
2617 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002618 * Set the language of a node, i.e. the values of the xml:lang
2619 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002620 */
2621void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002622xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002623 if (cur == NULL) return;
2624 switch(cur->type) {
2625 case XML_TEXT_NODE:
2626 case XML_CDATA_SECTION_NODE:
2627 case XML_COMMENT_NODE:
2628 case XML_DOCUMENT_NODE:
2629 case XML_DOCUMENT_TYPE_NODE:
2630 case XML_DOCUMENT_FRAG_NODE:
2631 case XML_NOTATION_NODE:
2632 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002633 case XML_DTD_NODE:
2634 case XML_ELEMENT_DECL:
2635 case XML_ATTRIBUTE_DECL:
2636 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002637 case XML_PI_NODE:
2638 case XML_ENTITY_REF_NODE:
2639 case XML_ENTITY_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002640#ifdef LIBXML_SGML_ENABLED
2641 case XML_SGML_DOCUMENT_NODE:
2642#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002643 return;
2644 case XML_ELEMENT_NODE:
2645 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002646 break;
2647 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002648 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2649}
2650
2651/**
2652 * xmlNodeGetLang:
2653 * @cur: the node being checked
2654 *
2655 * Searches the language of a node, i.e. the values of the xml:lang
2656 * attribute or the one carried by the nearest ancestor.
2657 *
2658 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002659 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002660 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002661xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002662xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002663 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002664
2665 while (cur != NULL) {
2666 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2667 if (lang != NULL)
2668 return(lang);
2669 cur = cur->parent;
2670 }
2671 return(NULL);
2672}
2673
2674/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002675 * xmlNodeGetSpacePreserve:
2676 * @cur: the node being checked
2677 *
2678 * Searches the language of a node, i.e. the values of the xml:space
2679 * attribute or the one carried by the nearest ancestor.
2680 *
2681 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2682 */
2683int
2684xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2685 xmlChar *space;
2686
2687 while (cur != NULL) {
2688 space = xmlGetProp(cur, BAD_CAST "xml:space");
2689 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002690 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002691 xmlFree(space);
2692 return(1);
2693 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002694 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002695 xmlFree(space);
2696 return(0);
2697 }
2698 xmlFree(space);
2699 }
2700 cur = cur->parent;
2701 }
2702 return(-1);
2703}
2704
2705/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002706 * xmlNodeSetName:
2707 * @cur: the node being changed
2708 * @name: the new tag name
2709 *
2710 * Searches the language of a node, i.e. the values of the xml:lang
2711 * attribute or the one carried by the nearest ancestor.
2712 */
2713void
2714xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2715 if (cur == NULL) return;
2716 if (name == NULL) return;
2717 switch(cur->type) {
2718 case XML_TEXT_NODE:
2719 case XML_CDATA_SECTION_NODE:
2720 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002721 case XML_DOCUMENT_TYPE_NODE:
2722 case XML_DOCUMENT_FRAG_NODE:
2723 case XML_NOTATION_NODE:
2724 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002725#ifdef LIBXML_SGML_ENABLED
2726 case XML_SGML_DOCUMENT_NODE:
2727#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002728 return;
2729 case XML_ELEMENT_NODE:
2730 case XML_ATTRIBUTE_NODE:
2731 case XML_PI_NODE:
2732 case XML_ENTITY_REF_NODE:
2733 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002734 case XML_DTD_NODE:
2735 case XML_DOCUMENT_NODE:
2736 case XML_ELEMENT_DECL:
2737 case XML_ATTRIBUTE_DECL:
2738 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002739 break;
2740 }
2741 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
2742 cur->name = xmlStrdup(name);
2743}
2744
2745/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00002746 * xmlNodeGetBase:
2747 * @doc: the document the node pertains to
2748 * @cur: the node being checked
2749 *
2750 * Searches for the BASE URL. The code should work on both XML
2751 * and HTML document even if base mechanisms are completely different.
2752 *
2753 * Returns a pointer to the base URL, or NULL if not found
2754 * It's up to the caller to free the memory.
2755 */
2756xmlChar *
2757xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
2758 xmlChar *base;
2759
2760 if ((cur == NULL) && (doc == NULL))
2761 return(NULL);
2762 if (doc == NULL) doc = cur->doc;
2763 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002764 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002765 while ((cur != NULL) && (cur->name != NULL)) {
Daniel Veillard39c7d712000-09-10 16:14:55 +00002766 if (cur->type == XML_ENTITY_DECL) {
2767 /* TODO: we are crossing entity boundaries */
2768 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00002769 if (cur->type != XML_ELEMENT_NODE) {
2770 cur = cur->next;
2771 continue;
2772 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00002773 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002774 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002775 continue;
2776 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00002777 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002778 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002779 continue;
2780 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00002781 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
2782 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00002783 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002784 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002785 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002786 if ((doc != NULL) && (doc->URL != NULL))
2787 return(xmlStrdup(doc->URL));
Daniel Veillard10a2c651999-12-12 13:03:50 +00002788 return(NULL);
2789 }
2790 while (cur != NULL) {
2791 base = xmlGetProp(cur, BAD_CAST "xml:base");
2792 if (base != NULL)
2793 return(base);
2794 cur = cur->parent;
2795 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002796 if ((doc != NULL) && (doc->URL != NULL))
2797 return(xmlStrdup(doc->URL));
Daniel Veillard10a2c651999-12-12 13:03:50 +00002798 return(NULL);
2799}
2800
2801/**
Daniel Veillard16253641998-10-28 22:58:05 +00002802 * xmlNodeGetContent:
2803 * @cur: the node being read
2804 *
2805 * Read the value of a node, this can be either the text carried
2806 * directly by this node if it's a TEXT node or the aggregate string
2807 * of the values carried by this node child's (TEXT and ENTITY_REF).
2808 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002809 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00002810 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00002811 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002812xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00002813xmlNodeGetContent(xmlNodePtr cur) {
2814 if (cur == NULL) return(NULL);
2815 switch (cur->type) {
2816 case XML_DOCUMENT_FRAG_NODE:
2817 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002818 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00002819 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002820 case XML_ATTRIBUTE_NODE: {
2821 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00002822 if (attr->parent != NULL)
2823 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002824 else
Daniel Veillardcf461992000-03-14 18:30:20 +00002825 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002826 break;
2827 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002828 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002829 case XML_PI_NODE:
2830 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002831#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00002832 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002833#else
2834 return(xmlStrdup(xmlBufferContent(cur->content)));
2835#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002836 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00002837 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002838 /*
2839 * Locate the entity, and get it's content
2840 * @@@
2841 */
2842 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00002843 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002844 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002845 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002846 case XML_DOCUMENT_TYPE_NODE:
2847 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002848 case XML_DTD_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002849#ifdef LIBXML_SGML_ENABLED
2850 case XML_SGML_DOCUMENT_NODE:
2851#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002852 return(NULL);
2853 case XML_ELEMENT_DECL:
2854 /* TODO !!! */
2855 return(NULL);
2856 case XML_ATTRIBUTE_DECL:
2857 /* TODO !!! */
2858 return(NULL);
2859 case XML_ENTITY_DECL:
2860 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00002861 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002862 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002863 case XML_TEXT_NODE:
2864 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002865#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00002866 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002867#else
2868 return(xmlStrdup(xmlBufferContent(cur->content)));
2869#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002870 return(NULL);
2871 }
2872 return(NULL);
2873}
2874
2875/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002876 * xmlNodeSetContent:
2877 * @cur: the node being modified
2878 * @content: the new value of the content
2879 *
2880 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002881 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002882void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002883xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002884 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002885#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002886 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002887#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002888 return;
2889 }
Daniel Veillard16253641998-10-28 22:58:05 +00002890 switch (cur->type) {
2891 case XML_DOCUMENT_FRAG_NODE:
2892 case XML_ELEMENT_NODE:
2893 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002894#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002895 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002896#else
2897 xmlBufferFree(cur->content);
2898#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002899 cur->content = NULL;
2900 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002901 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2902 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002903 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00002904 break;
2905 case XML_ATTRIBUTE_NODE:
2906 break;
2907 case XML_TEXT_NODE:
2908 case XML_CDATA_SECTION_NODE:
2909 case XML_ENTITY_REF_NODE:
2910 case XML_ENTITY_NODE:
2911 case XML_PI_NODE:
2912 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002913 if (cur->content != NULL) {
2914#ifndef XML_USE_BUFFER_CONTENT
2915 xmlFree(cur->content);
2916#else
2917 xmlBufferFree(cur->content);
2918#endif
2919 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002920 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2921 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002922 if (content != NULL) {
2923#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00002924 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002925#else
2926 cur->content = xmlBufferCreateSize(0);
2927 xmlBufferSetAllocationScheme(cur->content,
2928 xmlGetBufferAllocationScheme());
2929 xmlBufferAdd(cur->content, content, -1);
2930#endif
2931 } else
Daniel Veillard16253641998-10-28 22:58:05 +00002932 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002933 break;
Daniel Veillard16253641998-10-28 22:58:05 +00002934 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002935 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00002936 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002937#ifdef LIBXML_SGML_ENABLED
2938 case XML_SGML_DOCUMENT_NODE:
2939#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002940 break;
2941 case XML_NOTATION_NODE:
2942 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00002943 case XML_DTD_NODE:
2944 break;
2945 case XML_ELEMENT_DECL:
2946 /* TODO !!! */
2947 break;
2948 case XML_ATTRIBUTE_DECL:
2949 /* TODO !!! */
2950 break;
2951 case XML_ENTITY_DECL:
2952 /* TODO !!! */
2953 break;
Daniel Veillard16253641998-10-28 22:58:05 +00002954 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002955}
2956
Daniel Veillard97b58771998-10-20 06:14:16 +00002957/**
2958 * xmlNodeSetContentLen:
2959 * @cur: the node being modified
2960 * @content: the new value of the content
2961 * @len: the size of @content
2962 *
2963 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002964 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002965void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002966xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002967 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002968#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00002969 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002970#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002971 return;
2972 }
Daniel Veillard16253641998-10-28 22:58:05 +00002973 switch (cur->type) {
2974 case XML_DOCUMENT_FRAG_NODE:
2975 case XML_ELEMENT_NODE:
2976 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002977#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002978 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002979#else
2980 xmlBufferFree(cur->content);
2981#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002982 cur->content = NULL;
2983 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002984 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2985 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002986 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00002987 break;
2988 case XML_ATTRIBUTE_NODE:
2989 break;
2990 case XML_TEXT_NODE:
2991 case XML_CDATA_SECTION_NODE:
2992 case XML_ENTITY_REF_NODE:
2993 case XML_ENTITY_NODE:
2994 case XML_PI_NODE:
2995 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002996 case XML_NOTATION_NODE:
2997 if (cur->content != NULL) {
2998#ifndef XML_USE_BUFFER_CONTENT
2999 xmlFree(cur->content);
3000#else
3001 xmlBufferFree(cur->content);
3002#endif
3003 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003004 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3005 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003006 if (content != NULL) {
3007#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003008 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003009#else
3010 cur->content = xmlBufferCreateSize(len);
3011 xmlBufferSetAllocationScheme(cur->content,
3012 xmlGetBufferAllocationScheme());
3013 xmlBufferAdd(cur->content, content, len);
3014#endif
3015 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003016 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003017 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003018 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003019 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003020 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003021 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00003022#ifdef LIBXML_SGML_ENABLED
3023 case XML_SGML_DOCUMENT_NODE:
3024#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003025 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003026 case XML_ELEMENT_DECL:
3027 /* TODO !!! */
3028 break;
3029 case XML_ATTRIBUTE_DECL:
3030 /* TODO !!! */
3031 break;
3032 case XML_ENTITY_DECL:
3033 /* TODO !!! */
3034 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003035 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003036}
3037
Daniel Veillard97b58771998-10-20 06:14:16 +00003038/**
3039 * xmlNodeAddContentLen:
3040 * @cur: the node being modified
3041 * @content: extra content
3042 * @len: the size of @content
3043 *
3044 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003045 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003046void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003047xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003048 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003049#ifdef DEBUG_TREE
Daniel Veillard16253641998-10-28 22:58:05 +00003050 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003051#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003052 return;
3053 }
3054 if (len <= 0) return;
3055 switch (cur->type) {
3056 case XML_DOCUMENT_FRAG_NODE:
3057 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003058 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003059
Daniel Veillardcf461992000-03-14 18:30:20 +00003060 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003061 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003062 } else {
3063 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003064#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003065 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003066#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003067 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003068 xmlBufferContent(cur->content));
3069#endif
Daniel Veillard1e346af1999-02-22 10:33:01 +00003070 UPDATE_LAST_CHILD(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003071#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003072 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003073#else
3074 xmlBufferFree(cur->content);
3075#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003076 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003077 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003078 }
3079 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003080 newNode = xmlNewTextLen(content, len);
3081 if (newNode != NULL) {
3082 xmlAddChild(cur, newNode);
3083 if ((last != NULL) && (last->next == newNode)) {
3084 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003085 }
Daniel Veillard16253641998-10-28 22:58:05 +00003086 }
3087 break;
3088 }
3089 case XML_ATTRIBUTE_NODE:
3090 break;
3091 case XML_TEXT_NODE:
3092 case XML_CDATA_SECTION_NODE:
3093 case XML_ENTITY_REF_NODE:
3094 case XML_ENTITY_NODE:
3095 case XML_PI_NODE:
3096 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003097 case XML_NOTATION_NODE:
3098 if (content != NULL) {
3099#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003100 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003101#else
3102 xmlBufferAdd(cur->content, content, len);
3103#endif
3104 }
Daniel Veillard16253641998-10-28 22:58:05 +00003105 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003106 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003107 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003108 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00003109#ifdef LIBXML_SGML_ENABLED
3110 case XML_SGML_DOCUMENT_NODE:
3111#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003112 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003113 case XML_ELEMENT_DECL:
3114 case XML_ATTRIBUTE_DECL:
3115 case XML_ENTITY_DECL:
3116 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003117 }
3118}
3119
3120/**
3121 * xmlNodeAddContent:
3122 * @cur: the node being modified
3123 * @content: extra content
3124 *
3125 * Append the extra substring to the node content.
3126 */
3127void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003128xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003129 int len;
3130
3131 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003132#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00003133 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003134#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003135 return;
3136 }
Daniel Veillard16253641998-10-28 22:58:05 +00003137 if (content == NULL) return;
3138 len = xmlStrlen(content);
3139 xmlNodeAddContentLen(cur, content, len);
3140}
3141
3142/**
3143 * xmlTextMerge:
3144 * @first: the first text node
3145 * @second: the second text node being merged
3146 *
3147 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003148 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003149 */
3150xmlNodePtr
3151xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3152 if (first == NULL) return(second);
3153 if (second == NULL) return(first);
3154 if (first->type != XML_TEXT_NODE) return(first);
3155 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003156#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003157 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003158#else
3159 xmlNodeAddContent(first, xmlBufferContent(second->content));
3160#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003161 xmlUnlinkNode(second);
3162 xmlFreeNode(second);
3163 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003164}
3165
Daniel Veillard97b58771998-10-20 06:14:16 +00003166/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003167 * xmlGetNsList:
3168 * @doc: the document
3169 * @node: the current node
3170 *
3171 * Search all the namespace applying to a given element.
3172 * Returns an NULL terminated array of all the xmlNsPtr found
3173 * that need to be freed by the caller or NULL if no
3174 * namespace if defined
3175 */
3176xmlNsPtr *
3177xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3178 xmlNsPtr cur;
3179 xmlNsPtr *ret = NULL;
3180 int nbns = 0;
3181 int maxns = 10;
3182 int i;
3183
3184 while (node != NULL) {
3185 cur = node->nsDef;
3186 while (cur != NULL) {
3187 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003188 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003189 if (ret == NULL) {
3190 fprintf(stderr, "xmlGetNsList : out of memory!\n");
3191 return(NULL);
3192 }
3193 ret[nbns] = NULL;
3194 }
3195 for (i = 0;i < nbns;i++) {
3196 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003197 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003198 }
3199 if (i >= nbns) {
3200 if (nbns >= maxns) {
3201 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003202 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003203 (maxns + 1) * sizeof(xmlNsPtr));
3204 if (ret == NULL) {
3205 fprintf(stderr, "xmlGetNsList : realloc failed!\n");
3206 return(NULL);
3207 }
3208 }
3209 ret[nbns++] = cur;
3210 ret[nbns] = NULL;
3211 }
3212
3213 cur = cur->next;
3214 }
3215 node = node->parent;
3216 }
3217 return(ret);
3218}
3219
3220/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003221 * xmlSearchNs:
3222 * @doc: the document
3223 * @node: the current node
3224 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003225 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003226 * Search a Ns registered under a given name space for a document.
3227 * recurse on the parents until it finds the defined namespace
3228 * or return NULL otherwise.
3229 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003230 * We don't allow to cross entities boundaries. If you don't declare
3231 * the namespace within those you will be in troubles !!! A warning
3232 * is generated to cover this case.
3233 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003234 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003235 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003236xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003237xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003238 xmlNsPtr cur;
3239
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003240 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003241 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003242 if ((node->type == XML_ENTITY_REF_NODE) ||
3243 (node->type == XML_ENTITY_NODE) ||
3244 (node->type == XML_ENTITY_DECL))
3245 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003246 if (node->type == XML_ELEMENT_NODE) {
3247 cur = node->nsDef;
3248 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003249 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3250 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003251 return(cur);
3252 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003253 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003254 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003255 return(cur);
3256 cur = cur->next;
3257 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003258 }
3259 node = node->parent;
3260 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003261 return(NULL);
3262}
3263
Daniel Veillard97b58771998-10-20 06:14:16 +00003264/**
3265 * xmlSearchNsByHref:
3266 * @doc: the document
3267 * @node: the current node
3268 * @href: the namespace value
3269 *
3270 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3271 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003272 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003273 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003274xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003275xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003276 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003277 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003278
Daniel Veillard10a2c651999-12-12 13:03:50 +00003279 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003280 while (node != NULL) {
3281 cur = node->nsDef;
3282 while (cur != NULL) {
3283 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003284 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003285 /*
3286 * Check that the prefix is not shadowed between orig and node
3287 */
3288 xmlNodePtr check = orig;
3289 xmlNsPtr tst;
3290
3291 while (check != node) {
3292 tst = check->nsDef;
3293 while (tst != NULL) {
3294 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3295 goto shadowed;
3296 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003297 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003298 goto shadowed;
3299 tst = tst->next;
3300 }
3301 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003302 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003303 }
3304shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003305 cur = cur->next;
3306 }
3307 node = node->parent;
3308 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003309 return(NULL);
3310}
3311
3312/**
3313 * xmlNewReconciliedNs
3314 * @doc: the document
3315 * @tree: a node expected to hold the new namespace
3316 * @ns: the original namespace
3317 *
3318 * This function tries to locate a namespace definition in a tree
3319 * ancestors, or create a new namespace definition node similar to
3320 * @ns trying to reuse the same prefix. However if the given prefix is
3321 * null (default namespace) or reused within the subtree defined by
3322 * @tree or on one of its ancestors then a new prefix is generated.
3323 * Returns the (new) namespace definition or NULL in case of error
3324 */
3325xmlNsPtr
3326xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3327 xmlNsPtr def;
3328 xmlChar prefix[50];
3329 int counter = 1;
3330
3331 if (tree == NULL) {
3332#ifdef DEBUG_TREE
3333 fprintf(stderr, "xmlNewReconciliedNs : tree == NULL\n");
3334#endif
3335 return(NULL);
3336 }
3337 if (ns == NULL) {
3338#ifdef DEBUG_TREE
3339 fprintf(stderr, "xmlNewReconciliedNs : ns == NULL\n");
3340#endif
3341 return(NULL);
3342 }
3343 /*
3344 * Search an existing namespace definition inherited.
3345 */
3346 def = xmlSearchNsByHref(doc, tree, ns->href);
3347 if (def != NULL)
3348 return(def);
3349
3350 /*
3351 * Find a close prefix which is not already in use.
3352 * Let's strip namespace prefixes longer than 20 chars !
3353 */
3354 sprintf((char *) prefix, "%.20s", ns->prefix);
3355 def = xmlSearchNs(doc, tree, prefix);
3356 while (def != NULL) {
3357 if (counter > 1000) return(NULL);
3358 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3359 def = xmlSearchNs(doc, tree, prefix);
3360 }
3361
3362 /*
3363 * Ok, now we are ready to create a new one.
3364 */
3365 def = xmlNewNs(tree, ns->href, prefix);
3366 return(def);
3367}
3368
3369/**
3370 * xmlReconciliateNs
3371 * @doc: the document
3372 * @tree: a node defining the subtree to reconciliate
3373 *
3374 * This function checks that all the namespaces declared within the given
3375 * tree are properly declared. This is needed for example after Copy or Cut
3376 * and then paste operations. The subtree may still hold pointers to
3377 * namespace declarations outside the subtree or invalid/masked. As much
3378 * as possible the function try tu reuse the existing namespaces found in
3379 * the new environment. If not possible the new namespaces are redeclared
3380 * on @tree at the top of the given subtree.
3381 * Returns the number of namespace declarations created or -1 in case of error.
3382 */
3383int
3384xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3385 xmlNsPtr *oldNs = NULL;
3386 xmlNsPtr *newNs = NULL;
3387 int sizeCache = 0;
3388 int nbCache = 0;
3389
3390 xmlNsPtr n;
3391 xmlNodePtr node = tree;
3392 xmlAttrPtr attr;
3393 int ret = 0, i;
3394
3395 while (node != NULL) {
3396 /*
3397 * Reconciliate the node namespace
3398 */
3399 if (node->ns != NULL) {
3400 /*
3401 * initialize the cache if needed
3402 */
3403 if (sizeCache == 0) {
3404 sizeCache = 10;
3405 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3406 sizeof(xmlNsPtr));
3407 if (oldNs == NULL) {
3408 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3409 return(-1);
3410 }
3411 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3412 sizeof(xmlNsPtr));
3413 if (newNs == NULL) {
3414 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3415 xmlFree(oldNs);
3416 return(-1);
3417 }
3418 }
3419 for (i = 0;i < nbCache;i++) {
3420 if (oldNs[i] == node->ns) {
3421 node->ns = newNs[i];
3422 break;
3423 }
3424 }
3425 if (i == nbCache) {
3426 /*
3427 * Ok we need to recreate a new namespace definition
3428 */
3429 n = xmlNewReconciliedNs(doc, tree, node->ns);
3430 if (n != NULL) { /* :-( what if else ??? */
3431 /*
3432 * check if we need to grow the cache buffers.
3433 */
3434 if (sizeCache <= nbCache) {
3435 sizeCache *= 2;
3436 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3437 sizeof(xmlNsPtr));
3438 if (oldNs == NULL) {
3439 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3440 xmlFree(newNs);
3441 return(-1);
3442 }
3443 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3444 sizeof(xmlNsPtr));
3445 if (newNs == NULL) {
3446 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3447 xmlFree(oldNs);
3448 return(-1);
3449 }
3450 }
3451 newNs[nbCache] = n;
3452 oldNs[nbCache++] = node->ns;
3453 node->ns = n;
3454 }
3455 }
3456 }
3457 /*
3458 * now check for namespace hold by attributes on the node.
3459 */
3460 attr = node->properties;
3461 while (attr != NULL) {
3462 if (attr->ns != NULL) {
3463 /*
3464 * initialize the cache if needed
3465 */
3466 if (sizeCache == 0) {
3467 sizeCache = 10;
3468 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3469 sizeof(xmlNsPtr));
3470 if (oldNs == NULL) {
3471 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3472 return(-1);
3473 }
3474 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3475 sizeof(xmlNsPtr));
3476 if (newNs == NULL) {
3477 fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
3478 xmlFree(oldNs);
3479 return(-1);
3480 }
3481 }
3482 for (i = 0;i < nbCache;i++) {
3483 if (oldNs[i] == attr->ns) {
3484 node->ns = newNs[i];
3485 break;
3486 }
3487 }
3488 if (i == nbCache) {
3489 /*
3490 * Ok we need to recreate a new namespace definition
3491 */
3492 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3493 if (n != NULL) { /* :-( what if else ??? */
3494 /*
3495 * check if we need to grow the cache buffers.
3496 */
3497 if (sizeCache <= nbCache) {
3498 sizeCache *= 2;
3499 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3500 sizeof(xmlNsPtr));
3501 if (oldNs == NULL) {
3502 fprintf(stderr,
3503 "xmlReconciliateNs : memory pbm\n");
3504 xmlFree(newNs);
3505 return(-1);
3506 }
3507 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3508 sizeof(xmlNsPtr));
3509 if (newNs == NULL) {
3510 fprintf(stderr,
3511 "xmlReconciliateNs : memory pbm\n");
3512 xmlFree(oldNs);
3513 return(-1);
3514 }
3515 }
3516 newNs[nbCache] = n;
3517 oldNs[nbCache++] = attr->ns;
3518 attr->ns = n;
3519 }
3520 }
3521 }
3522 attr = attr->next;
3523 }
3524
3525 /*
3526 * Browse the full subtree, deep first
3527 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003528 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003529 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003530 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003531 } else if ((node != tree) && (node->next != NULL)) {
3532 /* then siblings */
3533 node = node->next;
3534 } else if (node != tree) {
3535 /* go up to parents->next if needed */
3536 while (node != tree) {
3537 if (node->parent != NULL)
3538 node = node->parent;
3539 if ((node != tree) && (node->next != NULL)) {
3540 node = node->next;
3541 break;
3542 }
3543 if (node->parent == NULL) {
3544 node = NULL;
3545 break;
3546 }
3547 }
3548 /* exit condition */
3549 if (node == tree)
3550 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003551 }
3552 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003553 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003554}
3555
Daniel Veillard97b58771998-10-20 06:14:16 +00003556/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003557 * xmlHasProp:
3558 * @node: the node
3559 * @name: the attribute name
3560 *
3561 * Search an attribute associated to a node
3562 * This function also looks in DTD attribute declaration for #FIXED or
3563 * default declaration values unless DTD use has been turned off.
3564 *
3565 * Returns the attribute or the attribute declaration or NULL if
3566 * neither was found.
3567 */
3568xmlAttrPtr
3569xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3570 xmlAttrPtr prop;
3571 xmlDocPtr doc;
3572
3573 if ((node == NULL) || (name == NULL)) return(NULL);
3574 /*
3575 * Check on the properties attached to the node
3576 */
3577 prop = node->properties;
3578 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003579 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003580 return(prop);
3581 }
3582 prop = prop->next;
3583 }
3584 if (!xmlCheckDTD) return(NULL);
3585
3586 /*
3587 * Check if there is a default declaration in the internal
3588 * or external subsets
3589 */
3590 doc = node->doc;
3591 if (doc != NULL) {
3592 xmlAttributePtr attrDecl;
3593 if (doc->intSubset != NULL) {
3594 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3595 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3596 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3597 if (attrDecl != NULL)
3598 return((xmlAttrPtr) attrDecl);
3599 }
3600 }
3601 return(NULL);
3602}
3603
3604/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003605 * xmlGetProp:
3606 * @node: the node
3607 * @name: the attribute name
3608 *
3609 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003610 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003611 * This function looks in DTD attribute declaration for #FIXED or
3612 * default declaration values unless DTD use has been turned off.
3613 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003614 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003615 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003616 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003617xmlChar *
3618xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003619 xmlAttrPtr prop;
3620 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003621
Daniel Veillard10a2c651999-12-12 13:03:50 +00003622 if ((node == NULL) || (name == NULL)) return(NULL);
3623 /*
3624 * Check on the properties attached to the node
3625 */
3626 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003627 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003628 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003629 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00003630
Daniel Veillardcf461992000-03-14 18:30:20 +00003631 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003632 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00003633 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00003634 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003635 prop = prop->next;
3636 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003637 if (!xmlCheckDTD) return(NULL);
3638
3639 /*
3640 * Check if there is a default declaration in the internal
3641 * or external subsets
3642 */
3643 doc = node->doc;
3644 if (doc != NULL) {
3645 xmlAttributePtr attrDecl;
3646 if (doc->intSubset != NULL) {
3647 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3648 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3649 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00003650 if (attrDecl != NULL)
3651 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003652 }
3653 }
3654 return(NULL);
3655}
3656
3657/**
3658 * xmlGetNsProp:
3659 * @node: the node
3660 * @name: the attribute name
3661 * @namespace: the URI of the namespace
3662 *
3663 * Search and get the value of an attribute associated to a node
3664 * This attribute has to be anchored in the namespace specified.
3665 * This does the entity substitution.
3666 * This function looks in DTD attribute declaration for #FIXED or
3667 * default declaration values unless DTD use has been turned off.
3668 *
3669 * Returns the attribute value or NULL if not found.
3670 * It's up to the caller to free the memory.
3671 */
3672xmlChar *
3673xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
3674 xmlAttrPtr prop = node->properties;
3675 xmlDocPtr doc;
3676 xmlNsPtr ns;
3677
3678 if (namespace == NULL)
3679 return(xmlGetProp(node, name));
3680 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003681 /*
3682 * One need to have
3683 * - same attribute names
3684 * - and the attribute carrying that namespace
3685 * or
3686 * no namespace on the attribute and the element carrying it
3687 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003688 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003689 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003690 (xmlStrEqual(node->ns->href, namespace))) ||
3691 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003692 xmlChar *ret;
3693
Daniel Veillardcf461992000-03-14 18:30:20 +00003694 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00003695 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
3696 return(ret);
3697 }
3698 prop = prop->next;
3699 }
3700 if (!xmlCheckDTD) return(NULL);
3701
3702 /*
3703 * Check if there is a default declaration in the internal
3704 * or external subsets
3705 */
3706 doc = node->doc;
3707 if (doc != NULL) {
3708 xmlAttributePtr attrDecl;
3709 if (doc->intSubset != NULL) {
3710 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3711 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3712 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3713
3714 if (attrDecl->prefix != NULL) {
3715 /*
3716 * The DTD declaration only allows a prefix search
3717 */
3718 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003719 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00003720 return(xmlStrdup(attrDecl->defaultValue));
3721 }
3722 }
3723 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003724 return(NULL);
3725}
3726
Daniel Veillard97b58771998-10-20 06:14:16 +00003727/**
Daniel Veillardccb09631998-10-27 06:21:04 +00003728 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00003729 * @node: the node
3730 * @name: the attribute name
3731 * @value: the attribute value
3732 *
3733 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003734 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003735 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003736xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003737xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003738 xmlAttrPtr prop = node->properties;
3739
3740 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003741 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003742 if (prop->children != NULL)
3743 xmlFreeNodeList(prop->children);
3744 prop->children = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00003745 if (value != NULL) {
3746 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00003747 xmlNodePtr tmp;
3748
Daniel Veillard51e3b151999-11-12 17:02:31 +00003749 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00003750 prop->children = xmlStringGetNodeList(node->doc, buffer);
3751 tmp = prop->children;
3752 while (tmp != NULL) {
3753 tmp->parent = (xmlNodePtr) prop;
3754 if (tmp->next == NULL)
3755 prop->last = tmp;
3756 tmp = tmp->next;
3757 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00003758 xmlFree(buffer);
3759 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003760 return(prop);
3761 }
3762 prop = prop->next;
3763 }
3764 prop = xmlNewProp(node, name, value);
3765 return(prop);
3766}
3767
Daniel Veillard97b58771998-10-20 06:14:16 +00003768/**
3769 * xmlNodeIsText:
3770 * @node: the node
3771 *
3772 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00003773 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00003774 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003775int
3776xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003777 if (node == NULL) return(0);
3778
Daniel Veillard0bef1311998-10-14 02:36:47 +00003779 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003780 return(0);
3781}
3782
Daniel Veillard97b58771998-10-20 06:14:16 +00003783/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00003784 * xmlIsBlankNode:
3785 * @node: the node
3786 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003787 * Checks whether this node is an empty or whitespace only
3788 * (and possibly ignorable) text-node.
3789 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00003790 * Returns 1 yes, 0 no
3791 */
3792int
3793xmlIsBlankNode(xmlNodePtr node) {
3794 xmlChar *cur;
3795 if (node == NULL) return(0);
3796
3797 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00003798 if (node->content == NULL) return(1);
Daniel Veillard3e6d2372000-03-04 11:39:43 +00003799 cur = node->content;
3800 while (*cur != 0) {
3801 if (!IS_BLANK(*cur)) return(0);
3802 cur++;
3803 }
3804
3805 return(1);
3806}
3807
3808/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00003809 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00003810 * @node: the node
3811 * @content: the content
3812 * @len: @content lenght
3813 *
3814 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00003815 */
Daniel Veillard97b58771998-10-20 06:14:16 +00003816
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003817void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003818xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003819 if (node == NULL) return;
3820
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003821 if ((node->type != XML_TEXT_NODE) &&
3822 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003823#ifdef DEBUG_TREE
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003824 fprintf(stderr, "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003825#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003826 return;
3827 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003828#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00003829 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003830#else
3831 xmlBufferAdd(node->content, content, len);
3832#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003833}
3834
3835/************************************************************************
3836 * *
3837 * Output : to a FILE or in memory *
3838 * *
3839 ************************************************************************/
3840
Daniel Veillard5099ae81999-04-21 20:12:07 +00003841#define BASE_BUFFER_SIZE 4000
3842
3843/**
3844 * xmlBufferCreate:
3845 *
3846 * routine to create an XML buffer.
3847 * returns the new structure.
3848 */
3849xmlBufferPtr
3850xmlBufferCreate(void) {
3851 xmlBufferPtr ret;
3852
Daniel Veillard6454aec1999-09-02 22:04:43 +00003853 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00003854 if (ret == NULL) {
3855 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3856 return(NULL);
3857 }
3858 ret->use = 0;
3859 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003860 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003861 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00003862 if (ret->content == NULL) {
3863 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00003864 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003865 return(NULL);
3866 }
3867 ret->content[0] = 0;
3868 return(ret);
3869}
3870
3871/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003872 * xmlBufferCreateSize:
3873 * @size: initial size of buffer
3874 *
3875 * routine to create an XML buffer.
3876 * returns the new structure.
3877 */
3878xmlBufferPtr
3879xmlBufferCreateSize(size_t size) {
3880 xmlBufferPtr ret;
3881
3882 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
3883 if (ret == NULL) {
3884 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3885 return(NULL);
3886 }
3887 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003888 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003889 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00003890 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003891 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
3892 if (ret->content == NULL) {
3893 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
3894 xmlFree(ret);
3895 return(NULL);
3896 }
3897 ret->content[0] = 0;
3898 } else
3899 ret->content = NULL;
3900 return(ret);
3901}
3902
3903/**
Daniel Veillard06047432000-04-24 11:33:38 +00003904 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003905 * @buf: the buffer to free
3906 * @scheme: allocation scheme to use
3907 *
3908 * Sets the allocation scheme for this buffer
3909 */
3910void
3911xmlBufferSetAllocationScheme(xmlBufferPtr buf,
3912 xmlBufferAllocationScheme scheme) {
3913 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003914#ifdef DEBUG_BUFFER
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003915 fprintf(stderr, "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003916#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003917 return;
3918 }
3919
3920 buf->alloc = scheme;
3921}
3922
3923/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00003924 * xmlBufferFree:
3925 * @buf: the buffer to free
3926 *
3927 * Frees an XML buffer.
3928 */
3929void
3930xmlBufferFree(xmlBufferPtr buf) {
3931 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003932#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00003933 fprintf(stderr, "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003934#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00003935 return;
3936 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003937 if (buf->content != NULL) {
3938#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00003939 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003940#else
3941 memset(buf->content, -1, buf->size);
3942#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00003943 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003944 }
3945 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003946 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00003947}
3948
3949/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003950 * xmlBufferEmpty:
3951 * @buf: the buffer
3952 *
3953 * empty a buffer.
3954 */
3955void
3956xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00003957 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003958 buf->use = 0;
3959 memset(buf->content, -1, buf->size);/* just for debug */
3960}
3961
3962/**
3963 * xmlBufferShrink:
3964 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003965 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003966 *
3967 * Remove the beginning of an XML buffer.
3968 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003969 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003970 */
3971int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00003972xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003973 if (len == 0) return(0);
3974 if (len > buf->use) return(-1);
3975
3976 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003977 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003978
3979 buf->content[buf->use] = 0;
3980 return(len);
3981}
3982
3983/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00003984 * xmlBufferGrow:
3985 * @buf: the buffer
3986 * @len: the minimum free sie to allocate
3987 *
3988 * Grow the available space of an XML buffer.
3989 *
3990 * Returns the new available space or -1 in case of error
3991 */
3992int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00003993xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00003994 int size;
3995 xmlChar *newbuf;
3996
3997 if (len <= buf->use) return(0);
3998
Daniel Veillardbe803962000-06-28 23:40:59 +00003999 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004000
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004001 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004002 if (newbuf == NULL) return(-1);
4003 buf->content = newbuf;
4004 buf->size = size;
4005 return(buf->size - buf->use);
4006}
4007
4008/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004009 * xmlBufferDump:
4010 * @file: the file output
4011 * @buf: the buffer to dump
4012 *
4013 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004014 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004015 */
4016int
4017xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4018 int ret;
4019
4020 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004021#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00004022 fprintf(stderr, "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004023#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004024 return(0);
4025 }
4026 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004027#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00004028 fprintf(stderr, "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004029#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004030 return(0);
4031 }
4032 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004033 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004034 return(ret);
4035}
4036
4037/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004038 * xmlBufferContent:
4039 * @buf: the buffer to resize
4040 *
4041 * Returns the internal content
4042 */
4043
4044const xmlChar*
4045xmlBufferContent(const xmlBufferPtr buf)
4046{
4047 if(!buf)
4048 return NULL;
4049
4050 return buf->content;
4051}
4052
4053/**
4054 * xmlBufferLength:
4055 * @buf: the buffer
4056 *
4057 * Returns the length of data in the internal content
4058 */
4059
4060int
4061xmlBufferLength(const xmlBufferPtr buf)
4062{
4063 if(!buf)
4064 return 0;
4065
4066 return buf->use;
4067}
4068
4069/**
4070 * xmlBufferResize:
4071 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004072 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004073 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004074 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004075 *
4076 * Returns 0 in case of problems, 1 otherwise
4077 */
4078int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004079xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004080{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004081 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004082 xmlChar* rebuf = NULL;
4083
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004084 /*take care of empty case*/
4085 newSize = (buf->size ? buf->size*2 : size);
4086
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004087 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004088 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004089 return 1;
4090
4091 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004092 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004093 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004094 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004095 break;
4096 case XML_BUFFER_ALLOC_EXACT:
4097 newSize = size+10;
4098 break;
4099 default:
4100 newSize = size+10;
4101 break;
4102 }
4103
4104 if (buf->content == NULL)
4105 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4106 else
4107 rebuf = (xmlChar *) xmlRealloc(buf->content,
4108 newSize * sizeof(xmlChar));
4109 if (rebuf == NULL) {
4110 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
4111 return 0;
4112 }
4113 buf->content = rebuf;
4114 buf->size = newSize;
4115
4116 return 1;
4117}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004118
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004119/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004120 * xmlBufferAdd:
4121 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004122 * @str: the xmlChar string
4123 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004124 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004125 * Add a string range to an XML buffer. if len == -1, the lenght of
4126 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004127 */
4128void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004129xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004130 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004131
4132 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004133#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00004134 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004135#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004136 return;
4137 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004138 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004139#ifdef DEBUG_BUFFER
Daniel Veillard10a2c651999-12-12 13:03:50 +00004140 fprintf(stderr, "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004141#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004142 return;
4143 }
4144 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004145
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004146 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004147 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004148
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004149 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004150
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004151 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004152 if (needSize > buf->size){
4153 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004154 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
4155 return;
4156 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004157 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004158
4159 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004160 buf->use += len;
4161 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004162}
4163
4164/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004165 * xmlBufferAddHead:
4166 * @buf: the buffer
4167 * @str: the xmlChar string
4168 * @len: the number of xmlChar to add
4169 *
4170 * Add a string range to the beginning of an XML buffer.
4171 * if len == -1, the lenght of @str is recomputed.
4172 */
4173void
4174xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004175 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004176
4177 if (str == NULL) {
4178#ifdef DEBUG_BUFFER
4179 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
4180#endif
4181 return;
4182 }
4183 if (len < -1) {
4184#ifdef DEBUG_BUFFER
4185 fprintf(stderr, "xmlBufferAdd: len < 0\n");
4186#endif
4187 return;
4188 }
4189 if (len == 0) return;
4190
4191 if (len < 0)
4192 len = xmlStrlen(str);
4193
4194 if (len <= 0) return;
4195
4196 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004197 if (needSize > buf->size){
4198 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardbe803962000-06-28 23:40:59 +00004199 fprintf(stderr, "xmlBufferAddHead : out of memory!\n");
4200 return;
4201 }
4202 }
4203
4204 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4205 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4206 buf->use += len;
4207 buf->content[buf->use] = 0;
4208}
4209
4210/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004211 * xmlBufferCat:
4212 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004213 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004214 *
4215 * Append a zero terminated string to an XML buffer.
4216 */
4217void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004218xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004219 if (str != NULL)
4220 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004221}
4222
4223/**
4224 * xmlBufferCCat:
4225 * @buf: the buffer to dump
4226 * @str: the C char string
4227 *
4228 * Append a zero terminated C string to an XML buffer.
4229 */
4230void
4231xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4232 const char *cur;
4233
4234 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004235#ifdef DEBUG_BUFFER
Daniel Veillard5099ae81999-04-21 20:12:07 +00004236 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004237#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004238 return;
4239 }
4240 for (cur = str;*cur != 0;cur++) {
4241 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004242 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004243 fprintf(stderr, "xmlBufferCCat : out of memory!\n");
4244 return;
4245 }
4246 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004247 buf->content[buf->use++] = *cur;
4248 }
4249}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004250
Daniel Veillard97b58771998-10-20 06:14:16 +00004251/**
4252 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004253 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004254 * @string: the string to add
4255 *
4256 * routine which manage and grows an output buffer. This one add
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004257 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004258 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004259void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004260xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004261 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004262}
4263
Daniel Veillard97b58771998-10-20 06:14:16 +00004264/**
4265 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004266 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004267 * @string: the string to add
4268 *
4269 * routine which manage and grows an output buffer. This one add
4270 * C chars at the end of the array.
4271 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004272void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004273xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4274 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004275}
4276
Daniel Veillard5099ae81999-04-21 20:12:07 +00004277
Daniel Veillard97b58771998-10-20 06:14:16 +00004278/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004279 * xmlBufferWriteQuotedString:
4280 * @buf: the XML buffer output
4281 * @string: the string to add
4282 *
4283 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004284 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004285 * quote or double-quotes internally
4286 */
4287void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004288xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004289 if (xmlStrchr(string, '"')) {
4290 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004291#ifdef DEBUG_BUFFER
Daniel Veillard011b63c1999-06-02 17:44:04 +00004292 fprintf(stderr,
4293 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004294#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004295 }
4296 xmlBufferCCat(buf, "'");
4297 xmlBufferCat(buf, string);
4298 xmlBufferCCat(buf, "'");
4299 } else {
4300 xmlBufferCCat(buf, "\"");
4301 xmlBufferCat(buf, string);
4302 xmlBufferCCat(buf, "\"");
4303 }
4304}
4305
4306
Daniel Veillardbe803962000-06-28 23:40:59 +00004307/************************************************************************
4308 * *
4309 * Dumping XML tree content to a simple buffer *
4310 * *
4311 ************************************************************************/
4312
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004313void
Daniel Veillardcf461992000-03-14 18:30:20 +00004314xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4315 int format);
4316static void
4317xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4318 int format);
4319void
4320htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4321
Daniel Veillard011b63c1999-06-02 17:44:04 +00004322/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004323 * xmlGlobalNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004324 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004325 * @cur: a namespace
4326 *
4327 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004328 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004329static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004330xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004331 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004332#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004333 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004334#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004335 return;
4336 }
4337 if (cur->type == XML_GLOBAL_NAMESPACE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004338 xmlBufferWriteChar(buf, "<?namespace");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004339 if (cur->href != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004340 xmlBufferWriteChar(buf, " href=");
4341 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004342 }
4343 if (cur->prefix != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004344 xmlBufferWriteChar(buf, " AS=");
4345 xmlBufferWriteQuotedString(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004346 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004347 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004348 }
4349}
4350
Daniel Veillard97b58771998-10-20 06:14:16 +00004351/**
4352 * xmlGlobalNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004353 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004354 * @cur: the first namespace
4355 *
4356 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004357 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004358static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004359xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004360 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004361 xmlGlobalNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004362 cur = cur->next;
4363 }
4364}
4365
Daniel Veillard97b58771998-10-20 06:14:16 +00004366/**
4367 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004368 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004369 * @cur: a namespace
4370 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004371 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004372 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004373 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004374static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004375xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004376 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004377#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004378 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004379#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004380 return;
4381 }
4382 if (cur->type == XML_LOCAL_NAMESPACE) {
4383 /* Within the context of an element attributes */
4384 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004385 xmlBufferWriteChar(buf, " xmlns:");
4386 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004387 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004388 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004389 xmlBufferWriteChar(buf, "=");
4390 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004391 }
4392}
4393
Daniel Veillard97b58771998-10-20 06:14:16 +00004394/**
4395 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004396 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004397 * @cur: the first namespace
4398 *
4399 * Dump a list of local Namespace definitions.
4400 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004401 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004402static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004403xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004404 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004405 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004406 cur = cur->next;
4407 }
4408}
4409
Daniel Veillard97b58771998-10-20 06:14:16 +00004410/**
4411 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004412 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004413 * @doc: the document
4414 *
4415 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004416 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004417static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004418xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4419 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004420#ifdef DEBUG_TREE
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004421 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004422#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004423 return;
4424 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004425 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004426 xmlBufferWriteCHAR(buf, dtd->name);
4427 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004428 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004429 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004430 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004431 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4432 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004433 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004434 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004435 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004436 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4437 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4438 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004439 return;
4440 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004441 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004442 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4443#if 0
4444 if (dtd->entities != NULL)
4445 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4446 if (dtd->notations != NULL)
4447 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4448 if (dtd->elements != NULL)
4449 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4450 if (dtd->attributes != NULL)
4451 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4452#endif
4453 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004454}
4455
Daniel Veillard97b58771998-10-20 06:14:16 +00004456/**
4457 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004458 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004459 * @doc: the document
4460 * @cur: the attribute pointer
4461 *
4462 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004463 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004464static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004465xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004466 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004467
Daniel Veillard260a68f1998-08-13 03:39:55 +00004468 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004469#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004470 fprintf(stderr, "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004471#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004472 return;
4473 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004474 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004475 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4476 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4477 xmlBufferWriteChar(buf, ":");
4478 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004479 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004480 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardccb09631998-10-27 06:21:04 +00004481 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004482 xmlBufferWriteChar(buf, "=");
4483 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004484 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004485 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004486 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004487 }
4488}
4489
Daniel Veillard97b58771998-10-20 06:14:16 +00004490/**
4491 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004492 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004493 * @doc: the document
4494 * @cur: the first attribute pointer
4495 *
4496 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004497 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004498static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004499xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004500 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004501#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004502 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004503#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004504 return;
4505 }
4506 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004507 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004508 cur = cur->next;
4509 }
4510}
4511
Daniel Veillard260a68f1998-08-13 03:39:55 +00004512
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004513
Daniel Veillard97b58771998-10-20 06:14:16 +00004514/**
4515 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004516 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004517 * @doc: the document
4518 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004519 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004520 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004521 *
4522 * Dump an XML node list, recursive behaviour,children are printed too.
4523 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004524static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004525xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4526 int format) {
4527 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004528
Daniel Veillard260a68f1998-08-13 03:39:55 +00004529 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004530#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004531 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004532#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004533 return;
4534 }
4535 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004536 if ((format) && (xmlIndentTreeOutput) &&
4537 (cur->type == XML_ELEMENT_NODE))
4538 for (i = 0;i < level;i++)
4539 xmlBufferWriteChar(buf, " ");
4540 xmlNodeDump(buf, doc, cur, level, format);
4541 if (format) {
4542 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004543 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004544 cur = cur->next;
4545 }
4546}
4547
Daniel Veillard97b58771998-10-20 06:14:16 +00004548/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004549 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004550 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004551 * @doc: the document
4552 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004553 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004554 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004555 *
4556 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004557 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004558void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004559xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4560 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004561 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004562 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004563
4564 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004565#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00004566 fprintf(stderr, "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004567#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004568 return;
4569 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004570 if (cur->type == XML_DTD_NODE) {
4571 xmlDtdDump(buf, (xmlDtdPtr) cur);
4572 return;
4573 }
4574 if (cur->type == XML_ELEMENT_DECL) {
4575 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
4576 return;
4577 }
4578 if (cur->type == XML_ATTRIBUTE_DECL) {
4579 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
4580 return;
4581 }
4582 if (cur->type == XML_ENTITY_DECL) {
4583 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
4584 return;
4585 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004586 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00004587 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004588 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004589
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004590#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004591 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004592#else
4593 buffer = xmlEncodeEntitiesReentrant(doc,
4594 xmlBufferContent(cur->content));
4595#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004596 if (buffer != NULL) {
4597 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004598 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004599 }
4600 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004601 return;
4602 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004603 if (cur->type == XML_PI_NODE) {
4604 if (cur->content != NULL) {
4605 xmlBufferWriteChar(buf, "<?");
4606 xmlBufferWriteCHAR(buf, cur->name);
4607 if (cur->content != NULL) {
4608 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004609#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00004610 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004611#else
4612 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4613#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00004614 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004615 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00004616 } else {
4617 xmlBufferWriteChar(buf, "<?");
4618 xmlBufferWriteCHAR(buf, cur->name);
4619 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004620 }
4621 return;
4622 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004623 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004624 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004625 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004626#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004627 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004628#else
4629 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4630#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004631 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004632 }
4633 return;
4634 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004635 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004636 xmlBufferWriteChar(buf, "&");
4637 xmlBufferWriteCHAR(buf, cur->name);
4638 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00004639 return;
4640 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004641 if (cur->type == XML_CDATA_SECTION_NODE) {
4642 xmlBufferWriteChar(buf, "<![CDATA[");
4643 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004644#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00004645 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004646#else
4647 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4648#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00004649 xmlBufferWriteChar(buf, "]]>");
4650 return;
4651 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004652
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004653 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004654 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004655 while (tmp != NULL) {
4656 if ((tmp->type == XML_TEXT_NODE) ||
4657 (tmp->type == XML_ENTITY_REF_NODE)) {
4658 format = 0;
4659 break;
4660 }
4661 tmp = tmp->next;
4662 }
4663 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004664 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004665 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004666 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4667 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004668 }
4669
Daniel Veillard5099ae81999-04-21 20:12:07 +00004670 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004671 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004672 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004673 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004674 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004675
Daniel Veillardcf461992000-03-14 18:30:20 +00004676 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00004677 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004678 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004679 return;
4680 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004681 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00004682 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004683 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004684
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004685#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004686 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004687#else
4688 buffer = xmlEncodeEntitiesReentrant(doc,
4689 xmlBufferContent(cur->content));
4690#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004691 if (buffer != NULL) {
4692 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004693 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004694 }
4695 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004696 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004697 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004698 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004699 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004700 if ((xmlIndentTreeOutput) && (format))
4701 for (i = 0;i < level;i++)
4702 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004703 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004704 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004705 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004706 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4707 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004708 }
4709
Daniel Veillard5099ae81999-04-21 20:12:07 +00004710 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004711 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004712}
4713
Daniel Veillard97b58771998-10-20 06:14:16 +00004714/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004715 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00004716 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004717 * @doc: the document
4718 * @cur: the current node
4719 *
4720 * Dump an XML/HTML node, recursive behaviour,children are printed too.
4721 */
4722void
4723xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
4724 xmlBufferPtr buf;
4725
4726 if (cur == NULL) {
4727#ifdef DEBUG_TREE
4728 fprintf(stderr, "xmlElemDump : cur == NULL\n");
4729#endif
4730 return;
4731 }
4732 if (doc == NULL) {
4733#ifdef DEBUG_TREE
4734 fprintf(stderr, "xmlElemDump : doc == NULL\n");
4735#endif
4736 }
4737 buf = xmlBufferCreate();
4738 if (buf == NULL) return;
4739 if ((doc != NULL) &&
4740 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00004741#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004742 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00004743#else
4744 printf("HTML support not compiled in\n");
4745#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004746 } else
4747 xmlNodeDump(buf, doc, cur, 0, 1);
4748 xmlBufferDump(f, buf);
4749 xmlBufferFree(buf);
4750}
4751
4752/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004753 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004754 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004755 * @cur: the document
4756 *
4757 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004758 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004759static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004760xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00004761 xmlBufferWriteChar(buf, "<?xml version=");
4762 if (cur->version != NULL)
4763 xmlBufferWriteQuotedString(buf, cur->version);
4764 else
4765 xmlBufferWriteChar(buf, "\"1.0\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004766 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004767 xmlBufferWriteChar(buf, " encoding=");
4768 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004769 }
4770 switch (cur->standalone) {
4771 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004772 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004773 break;
4774 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004775 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004776 break;
4777 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004778 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004779 if (cur->children != NULL) {
4780 xmlNodePtr child = cur->children;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004781
Daniel Veillard260a68f1998-08-13 03:39:55 +00004782 /* global namespace definitions, the old way */
4783 if (oldXMLWDcompatibility)
Daniel Veillard5099ae81999-04-21 20:12:07 +00004784 xmlGlobalNsListDump(buf, cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004785 else
4786 xmlUpgradeOldNs(cur);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004787
4788 while (child != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004789 xmlNodeDump(buf, cur, child, 0, 1);
4790 xmlBufferWriteChar(buf, "\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004791 child = child->next;
4792 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004793 }
4794}
4795
Daniel Veillardbe803962000-06-28 23:40:59 +00004796/************************************************************************
4797 * *
4798 * Dumping XML tree content to an I/O output buffer *
4799 * *
4800 ************************************************************************/
4801
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004802void
Daniel Veillardbe803962000-06-28 23:40:59 +00004803xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
4804 int level, int format, const char *encoding);
4805static void
4806xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
4807 int level, int format, const char *encoding);
4808/**
4809 * xmlGlobalNsDumpOutput:
4810 * @buf: the XML buffer output
4811 * @cur: a namespace
4812 *
4813 * Dump a global Namespace, this is the old version based on PIs.
4814 */
4815static void
4816xmlGlobalNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4817 if (cur == NULL) {
4818#ifdef DEBUG_TREE
4819 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
4820#endif
4821 return;
4822 }
4823 if (cur->type == XML_GLOBAL_NAMESPACE) {
4824 xmlOutputBufferWriteString(buf, "<?namespace");
4825 if (cur->href != NULL) {
4826 xmlOutputBufferWriteString(buf, " href=");
4827 xmlBufferWriteQuotedString(buf->buffer, cur->href);
4828 }
4829 if (cur->prefix != NULL) {
4830 xmlOutputBufferWriteString(buf, " AS=");
4831 xmlBufferWriteQuotedString(buf->buffer, cur->prefix);
4832 }
4833 xmlOutputBufferWriteString(buf, "?>\n");
4834 }
4835}
4836
4837/**
4838 * xmlGlobalNsListDumpOutput:
4839 * @buf: the XML buffer output
4840 * @cur: the first namespace
4841 *
4842 * Dump a list of global Namespace, this is the old version based on PIs.
4843 */
4844static void
4845xmlGlobalNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4846 while (cur != NULL) {
4847 xmlGlobalNsDumpOutput(buf, cur);
4848 cur = cur->next;
4849 }
4850}
4851
4852/**
4853 * xmlNsDumpOutput:
4854 * @buf: the XML buffer output
4855 * @cur: a namespace
4856 *
4857 * Dump a local Namespace definition.
4858 * Should be called in the context of attributes dumps.
4859 */
4860static void
4861xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4862 if (cur == NULL) {
4863#ifdef DEBUG_TREE
4864 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
4865#endif
4866 return;
4867 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00004868 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00004869 /* Within the context of an element attributes */
4870 if (cur->prefix != NULL) {
4871 xmlOutputBufferWriteString(buf, " xmlns:");
4872 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
4873 } else
4874 xmlOutputBufferWriteString(buf, " xmlns");
4875 xmlOutputBufferWriteString(buf, "=");
4876 xmlBufferWriteQuotedString(buf->buffer, cur->href);
4877 }
4878}
4879
4880/**
4881 * xmlNsListDumpOutput:
4882 * @buf: the XML buffer output
4883 * @cur: the first namespace
4884 *
4885 * Dump a list of local Namespace definitions.
4886 * Should be called in the context of attributes dumps.
4887 */
4888static void
4889xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
4890 while (cur != NULL) {
4891 xmlNsDumpOutput(buf, cur);
4892 cur = cur->next;
4893 }
4894}
4895
4896/**
4897 * xmlDtdDumpOutput:
4898 * @buf: the XML buffer output
4899 * @doc: the document
4900 * @encoding: an optional encoding string
4901 *
4902 * Dump the XML document DTD, if any.
4903 */
4904static void
4905xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
4906 if (dtd == NULL) {
4907#ifdef DEBUG_TREE
4908 fprintf(stderr, "xmlDtdDump : no internal subset\n");
4909#endif
4910 return;
4911 }
4912 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
4913 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
4914 if (dtd->ExternalID != NULL) {
4915 xmlOutputBufferWriteString(buf, " PUBLIC ");
4916 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
4917 xmlOutputBufferWriteString(buf, " ");
4918 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
4919 } else if (dtd->SystemID != NULL) {
4920 xmlOutputBufferWriteString(buf, " SYSTEM ");
4921 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
4922 }
4923 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4924 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4925 xmlOutputBufferWriteString(buf, ">");
4926 return;
4927 }
4928 xmlOutputBufferWriteString(buf, " [\n");
4929 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
4930#if 0
4931 if (dtd->entities != NULL)
4932 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4933 if (dtd->notations != NULL)
4934 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4935 if (dtd->elements != NULL)
4936 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4937 if (dtd->attributes != NULL)
4938 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4939#endif
4940 xmlOutputBufferWriteString(buf, "]>");
4941}
4942
4943/**
4944 * xmlAttrDumpOutput:
4945 * @buf: the XML buffer output
4946 * @doc: the document
4947 * @cur: the attribute pointer
4948 * @encoding: an optional encoding string
4949 *
4950 * Dump an XML attribute
4951 */
4952static void
4953xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
4954 const char *encoding) {
4955 xmlChar *value;
4956
4957 if (cur == NULL) {
4958#ifdef DEBUG_TREE
4959 fprintf(stderr, "xmlAttrDump : property == NULL\n");
4960#endif
4961 return;
4962 }
4963 xmlOutputBufferWriteString(buf, " ");
4964 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4965 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
4966 xmlOutputBufferWriteString(buf, ":");
4967 }
4968 xmlOutputBufferWriteString(buf, (const char *)cur->name);
4969 value = xmlNodeListGetString(doc, cur->children, 0);
4970 if (value) {
4971 xmlOutputBufferWriteString(buf, "=");
4972 xmlBufferWriteQuotedString(buf->buffer, value);
4973 xmlFree(value);
4974 } else {
4975 xmlOutputBufferWriteString(buf, "=\"\"");
4976 }
4977}
4978
4979/**
4980 * xmlAttrListDumpOutput:
4981 * @buf: the XML buffer output
4982 * @doc: the document
4983 * @cur: the first attribute pointer
4984 * @encoding: an optional encoding string
4985 *
4986 * Dump a list of XML attributes
4987 */
4988static void
4989xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
4990 xmlAttrPtr cur, const char *encoding) {
4991 if (cur == NULL) {
4992#ifdef DEBUG_TREE
4993 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
4994#endif
4995 return;
4996 }
4997 while (cur != NULL) {
4998 xmlAttrDumpOutput(buf, doc, cur, encoding);
4999 cur = cur->next;
5000 }
5001}
5002
5003
5004
5005/**
5006 * xmlNodeListDumpOutput:
5007 * @buf: the XML buffer output
5008 * @doc: the document
5009 * @cur: the first node
5010 * @level: the imbrication level for indenting
5011 * @format: is formatting allowed
5012 * @encoding: an optional encoding string
5013 *
5014 * Dump an XML node list, recursive behaviour,children are printed too.
5015 */
5016static void
5017xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5018 xmlNodePtr cur, int level, int format, const char *encoding) {
5019 int i;
5020
5021 if (cur == NULL) {
5022#ifdef DEBUG_TREE
5023 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
5024#endif
5025 return;
5026 }
5027 while (cur != NULL) {
5028 if ((format) && (xmlIndentTreeOutput) &&
5029 (cur->type == XML_ELEMENT_NODE))
5030 for (i = 0;i < level;i++)
5031 xmlOutputBufferWriteString(buf, " ");
5032 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5033 if (format) {
5034 xmlOutputBufferWriteString(buf, "\n");
5035 }
5036 cur = cur->next;
5037 }
5038}
5039
5040/**
5041 * xmlNodeDumpOutput:
5042 * @buf: the XML buffer output
5043 * @doc: the document
5044 * @cur: the current node
5045 * @level: the imbrication level for indenting
5046 * @format: is formatting allowed
5047 * @encoding: an optional encoding string
5048 *
5049 * Dump an XML node, recursive behaviour,children are printed too.
5050 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005051void
Daniel Veillardbe803962000-06-28 23:40:59 +00005052xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5053 int level, int format, const char *encoding) {
5054 int i;
5055 xmlNodePtr tmp;
5056
5057 if (cur == NULL) {
5058#ifdef DEBUG_TREE
5059 fprintf(stderr, "xmlNodeDump : node == NULL\n");
5060#endif
5061 return;
5062 }
5063 if (cur->type == XML_DTD_NODE) {
5064 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5065 return;
5066 }
5067 if (cur->type == XML_ELEMENT_DECL) {
5068 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5069 return;
5070 }
5071 if (cur->type == XML_ATTRIBUTE_DECL) {
5072 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5073 return;
5074 }
5075 if (cur->type == XML_ENTITY_DECL) {
5076 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5077 return;
5078 }
5079 if (cur->type == XML_TEXT_NODE) {
5080 if (cur->content != NULL) {
5081 xmlChar *buffer;
5082
5083#ifndef XML_USE_BUFFER_CONTENT
5084 if (encoding == NULL)
5085 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5086 else
5087 buffer = xmlEncodeSpecialChars(doc, cur->content);
5088#else
5089 if (encoding == NULL)
5090 buffer = xmlEncodeEntitiesReentrant(doc,
5091 xmlBufferContent(cur->content));
5092 else
5093 buffer = xmlEncodeSpecialChars(doc,
5094 xmlBufferContent(cur->content));
5095#endif
5096 if (buffer != NULL) {
5097 xmlOutputBufferWriteString(buf, (const char *)buffer);
5098 xmlFree(buffer);
5099 }
5100 }
5101 return;
5102 }
5103 if (cur->type == XML_PI_NODE) {
5104 if (cur->content != NULL) {
5105 xmlOutputBufferWriteString(buf, "<?");
5106 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5107 if (cur->content != NULL) {
5108 xmlOutputBufferWriteString(buf, " ");
5109#ifndef XML_USE_BUFFER_CONTENT
5110 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5111#else
5112 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5113#endif
5114 }
5115 xmlOutputBufferWriteString(buf, "?>");
5116 } else {
5117 xmlOutputBufferWriteString(buf, "<?");
5118 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5119 xmlOutputBufferWriteString(buf, "?>");
5120 }
5121 return;
5122 }
5123 if (cur->type == XML_COMMENT_NODE) {
5124 if (cur->content != NULL) {
5125 xmlOutputBufferWriteString(buf, "<!--");
5126#ifndef XML_USE_BUFFER_CONTENT
5127 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5128#else
5129 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5130#endif
5131 xmlOutputBufferWriteString(buf, "-->");
5132 }
5133 return;
5134 }
5135 if (cur->type == XML_ENTITY_REF_NODE) {
5136 xmlOutputBufferWriteString(buf, "&");
5137 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5138 xmlOutputBufferWriteString(buf, ";");
5139 return;
5140 }
5141 if (cur->type == XML_CDATA_SECTION_NODE) {
5142 xmlOutputBufferWriteString(buf, "<![CDATA[");
5143 if (cur->content != NULL)
5144#ifndef XML_USE_BUFFER_CONTENT
5145 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5146#else
5147 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5148#endif
5149 xmlOutputBufferWriteString(buf, "]]>");
5150 return;
5151 }
5152
5153 if (format == 1) {
5154 tmp = cur->children;
5155 while (tmp != NULL) {
5156 if ((tmp->type == XML_TEXT_NODE) ||
5157 (tmp->type == XML_ENTITY_REF_NODE)) {
5158 format = 0;
5159 break;
5160 }
5161 tmp = tmp->next;
5162 }
5163 }
5164 xmlOutputBufferWriteString(buf, "<");
5165 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5166 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5167 xmlOutputBufferWriteString(buf, ":");
5168 }
5169
5170 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5171 if (cur->nsDef)
5172 xmlNsListDumpOutput(buf, cur->nsDef);
5173 if (cur->properties != NULL)
5174 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5175
5176 if ((cur->content == NULL) && (cur->children == NULL) &&
5177 (!xmlSaveNoEmptyTags)) {
5178 xmlOutputBufferWriteString(buf, "/>");
5179 return;
5180 }
5181 xmlOutputBufferWriteString(buf, ">");
5182 if (cur->content != NULL) {
5183 xmlChar *buffer;
5184
5185#ifndef XML_USE_BUFFER_CONTENT
5186 if (encoding == NULL)
5187 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5188 else
5189 buffer = xmlEncodeSpecialChars(doc, cur->content);
5190#else
5191 if (encoding == NULL)
5192 buffer = xmlEncodeEntitiesReentrant(doc,
5193 xmlBufferContent(cur->content));
5194 else
5195 buffer = xmlEncodeSpecialChars(doc,
5196 xmlBufferContent(cur->content));
5197#endif
5198 if (buffer != NULL) {
5199 xmlOutputBufferWriteString(buf, (const char *)buffer);
5200 xmlFree(buffer);
5201 }
5202 }
5203 if (cur->children != NULL) {
5204 if (format) xmlOutputBufferWriteString(buf, "\n");
5205 xmlNodeListDumpOutput(buf, doc, cur->children,
5206 (level >= 0?level+1:-1), format, encoding);
5207 if ((xmlIndentTreeOutput) && (format))
5208 for (i = 0;i < level;i++)
5209 xmlOutputBufferWriteString(buf, " ");
5210 }
5211 xmlOutputBufferWriteString(buf, "</");
5212 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5213 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5214 xmlOutputBufferWriteString(buf, ":");
5215 }
5216
5217 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5218 xmlOutputBufferWriteString(buf, ">");
5219}
5220
5221/**
5222 * xmlDocContentDumpOutput:
5223 * @buf: the XML buffer output
5224 * @cur: the document
5225 * @encoding: an optional encoding string
5226 *
5227 * Dump an XML document.
5228 */
5229static void
5230xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
5231 const char *encoding) {
5232 xmlOutputBufferWriteString(buf, "<?xml version=");
5233 if (cur->version != NULL)
5234 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5235 else
5236 xmlOutputBufferWriteString(buf, "\"1.0\"");
5237 if (encoding == NULL) {
5238 if (cur->encoding != NULL)
5239 encoding = (const char *) cur->encoding;
5240 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005241 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005242 }
5243 if (encoding != NULL) {
5244 xmlOutputBufferWriteString(buf, " encoding=");
5245 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5246 }
5247 switch (cur->standalone) {
5248 case 0:
5249 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5250 break;
5251 case 1:
5252 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5253 break;
5254 }
5255 xmlOutputBufferWriteString(buf, "?>\n");
5256 if (cur->children != NULL) {
5257 xmlNodePtr child = cur->children;
5258
5259 /* global namespace definitions, the old way */
5260 if (oldXMLWDcompatibility)
5261 xmlGlobalNsListDumpOutput(buf, cur->oldNs);
5262 else
5263 xmlUpgradeOldNs(cur);
5264
5265 while (child != NULL) {
5266 xmlNodeDumpOutput(buf, cur, child, 0, 1, encoding);
5267 xmlOutputBufferWriteString(buf, "\n");
5268 child = child->next;
5269 }
5270 }
5271}
5272
5273/************************************************************************
5274 * *
5275 * Saving functions front-ends *
5276 * *
5277 ************************************************************************/
5278
Daniel Veillard97b58771998-10-20 06:14:16 +00005279/**
5280 * xmlDocDumpMemory:
5281 * @cur: the document
5282 * @mem: OUT: the memory pointer
5283 * @size: OUT: the memory lenght
5284 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005285 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005286 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005287 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005288void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005289xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005290 xmlBufferPtr buf;
5291
Daniel Veillard260a68f1998-08-13 03:39:55 +00005292 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005293#ifdef DEBUG_TREE
5294 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
5295#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005296 *mem = NULL;
5297 *size = 0;
5298 return;
5299 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005300 buf = xmlBufferCreate();
5301 if (buf == NULL) {
5302 *mem = NULL;
5303 *size = 0;
5304 return;
5305 }
5306 xmlDocContentDump(buf, cur);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005307 *mem = xmlStrndup(buf->content, buf->use);
Daniel Veillard5099ae81999-04-21 20:12:07 +00005308 *size = buf->use;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005309 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005310}
5311
Daniel Veillard97b58771998-10-20 06:14:16 +00005312/**
5313 * xmlGetDocCompressMode:
5314 * @doc: the document
5315 *
5316 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005317 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005318 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005319int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005320xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005321 if (doc == NULL) return(-1);
5322 return(doc->compression);
5323}
5324
Daniel Veillard97b58771998-10-20 06:14:16 +00005325/**
5326 * xmlSetDocCompressMode:
5327 * @doc: the document
5328 * @mode: the compression ratio
5329 *
5330 * set the compression ratio for a document, ZLIB based
5331 * Correct values: 0 (uncompressed) to 9 (max compression)
5332 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005333void
5334xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005335 if (doc == NULL) return;
5336 if (mode < 0) doc->compression = 0;
5337 else if (mode > 9) doc->compression = 9;
5338 else doc->compression = mode;
5339}
5340
Daniel Veillard97b58771998-10-20 06:14:16 +00005341/**
5342 * xmlGetCompressMode:
5343 *
5344 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005345 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005346 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005347int
5348 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005349 return(xmlCompressMode);
5350}
Daniel Veillard97b58771998-10-20 06:14:16 +00005351
5352/**
5353 * xmlSetCompressMode:
5354 * @mode: the compression ratio
5355 *
5356 * set the default compression mode used, ZLIB based
5357 * Correct values: 0 (uncompressed) to 9 (max compression)
5358 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005359void
5360xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005361 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005362 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005363 else xmlCompressMode = mode;
5364}
5365
Daniel Veillardbe803962000-06-28 23:40:59 +00005366/**
5367 * xmlDocDump:
5368 * @f: the FILE*
5369 * @cur: the document
5370 *
5371 * Dump an XML document to an open FILE.
5372 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005373 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005374 */
5375int
5376xmlDocDump(FILE *f, xmlDocPtr cur) {
5377 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005378 const char * encoding;
5379 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005380 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005381
Daniel Veillardbe803962000-06-28 23:40:59 +00005382 if (cur == NULL) {
5383#ifdef DEBUG_TREE
5384 fprintf(stderr, "xmlDocDump : document == NULL\n");
5385#endif
5386 return(-1);
5387 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005388 encoding = (const char *) cur->encoding;
5389
5390 if (encoding != NULL) {
5391 xmlCharEncoding enc;
5392
5393 enc = xmlParseCharEncoding(encoding);
5394
5395 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
5396 fprintf(stderr, "xmlDocDump: document not in UTF8\n");
5397 return(-1);
5398 }
5399 if (enc != XML_CHAR_ENCODING_UTF8) {
5400 handler = xmlFindCharEncodingHandler(encoding);
5401 if (handler == NULL) {
5402 xmlFree((char *) cur->encoding);
5403 cur->encoding = NULL;
5404 }
5405 }
5406 }
5407 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005408 if (buf == NULL) return(-1);
5409 xmlDocContentDumpOutput(buf, cur, NULL);
5410
5411 ret = xmlOutputBufferClose(buf);
5412 return(ret);
5413}
5414
5415/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005416 * xmlSaveFileTo:
5417 * @buf: an output I/O buffer
5418 * @cur: the document
5419 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5420 *
5421 * Dump an XML document to an I/O buffer.
5422 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005423 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005424 */
5425int
5426xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5427 int ret;
5428
5429 if (buf == NULL) return(0);
5430 xmlDocContentDumpOutput(buf, cur, encoding);
5431 ret = xmlOutputBufferClose(buf);
5432 return(ret);
5433}
5434
5435/**
5436 * xmlSaveFileEnc:
5437 * @filename: the filename (or URL)
5438 * @cur: the document
5439 * @encoding: the name of an encoding (or NULL)
5440 *
5441 * Dump an XML document, converting it to the given encoding
5442 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005443 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005444 */
5445int
5446xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5447 xmlOutputBufferPtr buf;
5448 xmlCharEncodingHandlerPtr handler = NULL;
5449 int ret;
5450
5451 if (encoding != NULL) {
5452 xmlCharEncoding enc;
5453
5454 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005455 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
5456 fprintf(stderr, "xmlSaveFileEnc: document not in UTF8\n");
5457 return(-1);
5458 }
5459 if (enc != XML_CHAR_ENCODING_UTF8) {
5460 handler = xmlFindCharEncodingHandler(encoding);
5461 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005462 return(-1);
5463 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005464 }
5465 }
5466
5467 /*
5468 * save the content to a temp buffer.
5469 */
5470 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
5471 if (buf == NULL) return(0);
5472
5473 xmlDocContentDumpOutput(buf, cur, encoding);
5474
5475 ret = xmlOutputBufferClose(buf);
5476 return(ret);
5477}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005478
5479/**
5480 * xmlSaveFile:
5481 * @filename: the filename (or URL)
5482 * @cur: the document
5483 *
5484 * Dump an XML document to a file. Will use compression if
5485 * compiled in and enabled. If @filename is "-" the stdout file is
5486 * used.
5487 * returns: the number of byte written or -1 in case of failure.
5488 */
5489int
5490xmlSaveFile(const char *filename, xmlDocPtr cur) {
5491 xmlOutputBufferPtr buf;
5492 const char *encoding;
5493 xmlCharEncodingHandlerPtr handler = NULL;
5494 int ret;
5495
5496 if (cur == NULL)
5497 return(-1);
5498 encoding = (const char *) cur->encoding;
5499
5500 /*
5501 * save the content to a temp buffer.
5502 */
5503#ifdef HAVE_ZLIB_H
5504 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00005505#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005506 if (encoding != NULL) {
5507 xmlCharEncoding enc;
5508
5509 enc = xmlParseCharEncoding(encoding);
5510
5511 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
5512 fprintf(stderr, "xmlSaveFile: document not in UTF8\n");
5513 return(-1);
5514 }
5515 if (enc != XML_CHAR_ENCODING_UTF8) {
5516 handler = xmlFindCharEncodingHandler(encoding);
5517 if (handler == NULL) {
5518 xmlFree((char *) cur->encoding);
5519 cur->encoding = NULL;
5520 }
5521 }
5522 }
5523
5524 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
5525 if (buf == NULL) return(0);
5526
5527 xmlDocContentDumpOutput(buf, cur, NULL);
5528
5529 ret = xmlOutputBufferClose(buf);
5530 return(ret);
5531}
5532