blob: b4b7557647d7729329f8a86aed636cadf67b7eff [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillardce6e98d2000-11-25 09:54:49 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000012 */
13
Daniel Veillard7f7d1111999-09-22 09:46:25 +000014#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000015#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#else
Daniel Veillard151b1b01998-09-23 00:49:46 +000017#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#endif
19
Daniel Veillard260a68f1998-08-13 03:39:55 +000020#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include <string.h> /* for memset() only ! */
22
Daniel Veillard7f7d1111999-09-22 09:46:25 +000023#ifdef HAVE_CTYPE_H
24#include <ctype.h>
25#endif
26#ifdef HAVE_STDLIB_H
27#include <stdlib.h>
28#endif
Daniel Veillard151b1b01998-09-23 00:49:46 +000029#ifdef HAVE_ZLIB_H
30#include <zlib.h>
31#endif
32
Daniel Veillard361d8452000-04-03 19:48:13 +000033#include <libxml/xmlmemory.h>
34#include <libxml/tree.h>
35#include <libxml/parser.h>
36#include <libxml/entities.h>
37#include <libxml/valid.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000038#include <libxml/xmlerror.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000039
Daniel Veillardf6eea272001-01-18 12:17:12 +000040xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
41xmlChar xmlStringTextNoenc[] =
42 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
43xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +000044int oldXMLWDcompatibility = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +000045int xmlIndentTreeOutput = 0;
Daniel Veillardf5c2c871999-12-01 09:51:45 +000046xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
Daniel Veillard260a68f1998-08-13 03:39:55 +000047
Daniel Veillard15a8df41998-09-24 19:15:06 +000048static int xmlCompressMode = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +000049static int xmlCheckDTD = 1;
Daniel Veillarde41f2b72000-01-30 20:00:07 +000050int xmlSaveNoEmptyTags = 0;
Daniel Veillard3e6d2372000-03-04 11:39:43 +000051
52#define IS_BLANK(c) \
53 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
Daniel Veillard15a8df41998-09-24 19:15:06 +000054
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000055#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
Daniel Veillardcf461992000-03-14 18:30:20 +000056 xmlNodePtr ulccur = (n)->children; \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000057 if (ulccur == NULL) { \
58 (n)->last = NULL; \
59 } else { \
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000060 while (ulccur->next != NULL) { \
61 ulccur->parent = (n); \
62 ulccur = ulccur->next; \
63 } \
64 ulccur->parent = (n); \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000065 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000066}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000067
Daniel Veillardad8f99d2000-01-15 14:20:03 +000068/* #define DEBUG_BUFFER */
69/* #define DEBUG_TREE */
70
Daniel Veillard260a68f1998-08-13 03:39:55 +000071/************************************************************************
72 * *
73 * Allocation and deallocation of basic structures *
74 * *
75 ************************************************************************/
76
Daniel Veillard97b58771998-10-20 06:14:16 +000077/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +000078 * xmlSetBufferAllocationScheme:
79 * @scheme: allocation method to use
80 *
81 * Set the buffer allocation method. Types are
82 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
83 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
84 * improves performance
85 */
86void
87xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
88 xmlBufferAllocScheme = scheme;
89}
90
91/**
92 * xmlGetBufferAllocationScheme:
93 *
94 * Types are
95 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
96 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
97 * improves performance
98 *
99 * Returns the current allocation scheme
100 */
101xmlBufferAllocationScheme
102xmlGetBufferAllocationScheme() {
103 return xmlBufferAllocScheme;
104}
105
106/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000107 * xmlNewNs:
108 * @node: the element carrying the namespace
109 * @href: the URI associated
110 * @prefix: the prefix for the namespace
111 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000112 * Creation of a new Namespace. This function will refuse to create
113 * a namespace with a similar prefix than an existing one present on this
114 * node.
Daniel Veillarde0854c32000-08-27 21:12:29 +0000115 * We use href==NULL in the case of an element creation where the namespace
116 * was not defined.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000117 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000118 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000119xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000120xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000121 xmlNsPtr cur;
122
Daniel Veillard260a68f1998-08-13 03:39:55 +0000123 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000124 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000125 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000126 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000127 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000128 xmlGenericError(xmlGenericErrorContext,
129 "xmlNewNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000130 return(NULL);
131 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000132 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000133 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000134
Daniel Veillard260a68f1998-08-13 03:39:55 +0000135 if (href != NULL)
136 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137 if (prefix != NULL)
138 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139
140 /*
141 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000142 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000143 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000144 if (node != NULL) {
145 if (node->nsDef == NULL) {
146 node->nsDef = cur;
147 } else {
148 xmlNsPtr prev = node->nsDef;
149
Daniel Veillard0142b842000-01-14 14:45:24 +0000150 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000151 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000152 xmlFreeNs(cur);
153 return(NULL);
154 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000155 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000156 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000157 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000158 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard686d6b62000-01-03 11:08:02 +0000159 xmlFreeNs(cur);
160 return(NULL);
161 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000162 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000163 prev->next = cur;
164 }
165 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000166 return(cur);
167}
168
Daniel Veillard97b58771998-10-20 06:14:16 +0000169/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000170 * xmlSetNs:
171 * @node: a node in the document
172 * @ns: a namespace pointer
173 *
174 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000175 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000176void
177xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000178 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000179#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000180 xmlGenericError(xmlGenericErrorContext,
181 "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000182#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000183 return;
184 }
185 node->ns = ns;
186}
187
Daniel Veillard97b58771998-10-20 06:14:16 +0000188/**
189 * xmlFreeNs:
190 * @cur: the namespace pointer
191 *
192 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000193 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000194void
195xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000196 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000197#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000198 xmlGenericError(xmlGenericErrorContext,
199 "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000200#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000201 return;
202 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000203 if (cur->href != NULL) xmlFree((char *) cur->href);
204 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000205 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000206 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000207}
208
Daniel Veillard97b58771998-10-20 06:14:16 +0000209/**
210 * xmlFreeNsList:
211 * @cur: the first namespace pointer
212 *
213 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000214 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000215void
216xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000217 xmlNsPtr next;
218 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000219#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000220 xmlGenericError(xmlGenericErrorContext,
221 "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000222#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000223 return;
224 }
225 while (cur != NULL) {
226 next = cur->next;
227 xmlFreeNs(cur);
228 cur = next;
229 }
230}
231
Daniel Veillard97b58771998-10-20 06:14:16 +0000232/**
233 * xmlNewDtd:
234 * @doc: the document pointer
235 * @name: the DTD name
236 * @ExternalID: the external ID
237 * @SystemID: the system ID
238 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000239 * Creation of a new DTD for the external subset. To create an
240 * internal subset, use xmlCreateIntSubset().
241 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000242 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000243 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000244xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000245xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
246 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000247 xmlDtdPtr cur;
248
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000250#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000251 xmlGenericError(xmlGenericErrorContext,
252 "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000253 /* !!! */ (char *) name, doc->name,
254 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000255#endif
256 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000257 }
258
259 /*
260 * Allocate a new DTD and fill the fields.
261 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000262 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000263 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000264 xmlGenericError(xmlGenericErrorContext,
265 "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000266 return(NULL);
267 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000268 memset(cur, 0 , sizeof(xmlDtd));
269 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000270
271 if (name != NULL)
272 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000273 if (ExternalID != NULL)
274 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 if (SystemID != NULL)
276 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000277 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000278 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000279 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000280
281 return(cur);
282}
283
284/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000285 * xmlGetIntSubset:
286 * @doc: the document pointer
287 *
288 * Get the internal subset of a document
289 * Returns a pointer to the DTD structure or NULL if not found
290 */
291
292xmlDtdPtr
293xmlGetIntSubset(xmlDocPtr doc) {
294 xmlNodePtr cur;
295
296 if (doc == NULL)
297 return(NULL);
298 cur = doc->children;
299 while (cur != NULL) {
300 if (cur->type == XML_DTD_NODE)
301 return((xmlDtdPtr) cur);
302 cur = cur->next;
303 }
304 return((xmlDtdPtr) doc->intSubset);
305}
306
307/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000308 * xmlCreateIntSubset:
309 * @doc: the document pointer
310 * @name: the DTD name
311 * @ExternalID: the external ID
312 * @SystemID: the system ID
313 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000314 * Create the internal subset of a document
315 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000316 */
317xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000318xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
319 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000320 xmlDtdPtr cur;
321
Daniel Veillardcf461992000-03-14 18:30:20 +0000322 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000323#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000324 xmlGenericError(xmlGenericErrorContext,
325
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000326 "xmlCreateIntSubset(): document %s already have an internal subset\n",
327 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000328#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000329 return(NULL);
330 }
331
332 /*
333 * Allocate a new DTD and fill the fields.
334 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000335 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000336 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000337 xmlGenericError(xmlGenericErrorContext,
338 "xmlNewDtd : malloc failed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000339 return(NULL);
340 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000341 memset(cur, 0, sizeof(xmlDtd));
342 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000343
344 if (name != NULL)
345 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000346 if (ExternalID != NULL)
347 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000348 if (SystemID != NULL)
349 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000350 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000351 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000352 cur->parent = doc;
353 cur->doc = doc;
354 if (doc->children == NULL) {
355 doc->children = (xmlNodePtr) cur;
356 doc->last = (xmlNodePtr) cur;
357 } else {
358 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000359
Daniel Veillardb8f25c92000-08-19 19:52:36 +0000360 if (doc->type == XML_HTML_DOCUMENT_NODE) {
361 prev = doc->children;
362 prev->prev = (xmlNodePtr) cur;
363 cur->next = prev;
364 doc->children = (xmlNodePtr) cur;
365 } else {
366 prev = doc->last;
367 prev->next = (xmlNodePtr) cur;
368 cur->prev = prev;
369 doc->last = (xmlNodePtr) cur;
370 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000371 }
372 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000373 return(cur);
374}
375
Daniel Veillard97b58771998-10-20 06:14:16 +0000376/**
377 * xmlFreeDtd:
378 * @cur: the DTD structure to free up
379 *
380 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000381 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000382void
383xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000384 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000385#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000386 xmlGenericError(xmlGenericErrorContext,
387 "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000388#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000389 return;
390 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000391 if (cur->children != NULL) {
392 xmlNodePtr next, c = cur->children;
393
394 /*
395 * Cleanup all the DTD comments they are not in the Dtd
396 * indexes.
397 */
398 while (c != NULL) {
399 next = c->next;
400 if (c->type == XML_COMMENT_NODE) {
401 xmlUnlinkNode(c);
402 xmlFreeNode(c);
403 }
404 c = next;
405 }
406 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000407 if (cur->name != NULL) xmlFree((char *) cur->name);
408 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
409 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000410 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000411 if (cur->notations != NULL)
412 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000413
Daniel Veillard260a68f1998-08-13 03:39:55 +0000414 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000415 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000416 if (cur->attributes != NULL)
417 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 if (cur->entities != NULL)
419 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard126f2792000-10-24 17:10:12 +0000420 if (cur->pentities != NULL)
421 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000422
Daniel Veillard260a68f1998-08-13 03:39:55 +0000423 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000424 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000425}
426
Daniel Veillard97b58771998-10-20 06:14:16 +0000427/**
428 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000429 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000430 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000431 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000432 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000433xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000434xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000435 xmlDocPtr cur;
436
Daniel Veillard7eda8452000-10-14 23:38:43 +0000437 if (version == NULL)
438 version = (const xmlChar *) "1.0";
Daniel Veillard260a68f1998-08-13 03:39:55 +0000439
440 /*
441 * Allocate a new document and fill the fields.
442 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000443 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000444 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000445 xmlGenericError(xmlGenericErrorContext,
446 "xmlNewDoc : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000447 return(NULL);
448 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000449 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000450 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000451
Daniel Veillard260a68f1998-08-13 03:39:55 +0000452 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000453 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000454 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000455 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000456 return(cur);
457}
458
Daniel Veillard97b58771998-10-20 06:14:16 +0000459/**
460 * xmlFreeDoc:
461 * @cur: pointer to the document
462 * @:
463 *
464 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000465 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000466void
467xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000468 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000469#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000470 xmlGenericError(xmlGenericErrorContext,
471 "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000472#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000473 return;
474 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000475 if (cur->version != NULL) xmlFree((char *) cur->version);
476 if (cur->name != NULL) xmlFree((char *) cur->name);
477 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000478 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000479 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
480 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000481 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000482 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000483 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000484 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000485 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000486 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000487}
488
Daniel Veillard97b58771998-10-20 06:14:16 +0000489/**
Daniel Veillard16253641998-10-28 22:58:05 +0000490 * xmlStringLenGetNodeList:
491 * @doc: the document
492 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000493 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000494 *
495 * Parse the value string and build the node list associated. Should
496 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000497 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000498 */
499xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000500xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000501 xmlNodePtr ret = NULL, last = NULL;
502 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000503 xmlChar *val;
504 const xmlChar *cur = value;
505 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000506 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000507
508 if (value == NULL) return(NULL);
509
510 q = cur;
511 while ((*cur != 0) && (cur - value < len)) {
512 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000513 /*
514 * Save the current text.
515 */
Daniel Veillard16253641998-10-28 22:58:05 +0000516 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000517 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
518 xmlNodeAddContentLen(last, q, cur - q);
519 } else {
520 node = xmlNewDocTextLen(doc, q, cur - q);
521 if (node == NULL) return(ret);
522 if (last == NULL)
523 last = ret = node;
524 else {
525 last->next = node;
526 node->prev = last;
527 last = node;
528 }
Daniel Veillard16253641998-10-28 22:58:05 +0000529 }
530 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000531 /*
532 * Read the entity string
533 */
Daniel Veillard16253641998-10-28 22:58:05 +0000534 cur++;
535 q = cur;
536 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
537 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000538#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000540 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000541#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000542 return(ret);
543 }
544 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000545 /*
546 * Predefined entities don't generate nodes
547 */
Daniel Veillard16253641998-10-28 22:58:05 +0000548 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000549 ent = xmlGetDocEntity(doc, val);
550 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000551 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000552 if (last == NULL) {
553 node = xmlNewDocText(doc, ent->content);
554 last = ret = node;
555 } else
556 xmlNodeAddContent(last, ent->content);
557
558 } else {
559 /*
560 * Create a new REFERENCE_REF node
561 */
562 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000563 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000564 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000565 return(ret);
566 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000567 if (last == NULL)
568 last = ret = node;
569 else {
570 last->next = node;
571 node->prev = last;
572 last = node;
573 }
Daniel Veillard16253641998-10-28 22:58:05 +0000574 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000575 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000576 }
577 cur++;
578 q = cur;
579 } else
580 cur++;
581 }
582 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000583 /*
584 * Handle the last piece of text.
585 */
586 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
587 xmlNodeAddContentLen(last, q, cur - q);
588 } else {
589 node = xmlNewDocTextLen(doc, q, cur - q);
590 if (node == NULL) return(ret);
591 if (last == NULL)
592 last = ret = node;
593 else {
594 last->next = node;
595 node->prev = last;
596 last = node;
597 }
Daniel Veillard16253641998-10-28 22:58:05 +0000598 }
599 }
600 return(ret);
601}
602
603/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000604 * xmlStringGetNodeList:
605 * @doc: the document
606 * @value: the value of the attribute
607 *
608 * Parse the value string and build the node list associated. Should
609 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000610 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000611 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000612xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000613xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000614 xmlNodePtr ret = NULL, last = NULL;
615 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000616 xmlChar *val;
617 const xmlChar *cur = value;
618 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000619 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000620
621 if (value == NULL) return(NULL);
622
623 q = cur;
624 while (*cur != 0) {
625 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000626 /*
627 * Save the current text.
628 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000629 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000630 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
631 xmlNodeAddContentLen(last, q, cur - q);
632 } else {
633 node = xmlNewDocTextLen(doc, q, cur - q);
634 if (node == NULL) return(ret);
635 if (last == NULL)
636 last = ret = node;
637 else {
638 last->next = node;
639 node->prev = last;
640 last = node;
641 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000642 }
643 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000644 /*
645 * Read the entity string
646 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000647 cur++;
648 q = cur;
649 while ((*cur != 0) && (*cur != ';')) cur++;
650 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000651#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000652 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardccb09631998-10-27 06:21:04 +0000653 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000654#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000655 return(ret);
656 }
657 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000658 /*
659 * Predefined entities don't generate nodes
660 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000661 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000662 ent = xmlGetDocEntity(doc, val);
663 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000664 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000665 if (last == NULL) {
666 node = xmlNewDocText(doc, ent->content);
667 last = ret = node;
668 } else
669 xmlNodeAddContent(last, ent->content);
670
671 } else {
672 /*
673 * Create a new REFERENCE_REF node
674 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000675 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000676 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000678 return(ret);
679 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000680 if (last == NULL)
681 last = ret = node;
682 else {
683 last->next = node;
684 node->prev = last;
685 last = node;
686 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000687 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000688 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000689 }
690 cur++;
691 q = cur;
692 } else
693 cur++;
694 }
695 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000696 /*
697 * Handle the last piece of text.
698 */
699 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
700 xmlNodeAddContentLen(last, q, cur - q);
701 } else {
702 node = xmlNewDocTextLen(doc, q, cur - q);
703 if (node == NULL) return(ret);
704 if (last == NULL)
705 last = ret = node;
706 else {
707 last->next = node;
708 node->prev = last;
709 last = node;
710 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000711 }
712 }
713 return(ret);
714}
715
716/**
717 * xmlNodeListGetString:
718 * @doc: the document
719 * @list: a Node list
720 * @inLine: should we replace entity contents or show their external form
721 *
722 * Returns the string equivalent to the text contained in the Node list
723 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000724 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000725 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000726xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000727xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000728 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000729 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000730 xmlEntityPtr ent;
731
732 if (list == NULL) return(NULL);
733
734 while (node != NULL) {
Daniel Veillard87b95392000-08-12 21:12:04 +0000735 if ((node->type == XML_TEXT_NODE) ||
736 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000737 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000738#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000739 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000740#else
741 ret = xmlStrcat(ret, xmlBufferContent(node->content));
742#endif
743 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000744 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000745
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000746#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000747 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000748#else
749 buffer = xmlEncodeEntitiesReentrant(doc,
750 xmlBufferContent(node->content));
751#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000752 if (buffer != NULL) {
753 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000754 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000755 }
756 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000757 } else if (node->type == XML_ENTITY_REF_NODE) {
758 if (inLine) {
759 ent = xmlGetDocEntity(doc, node->name);
760 if (ent != NULL)
761 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000762 else {
763#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000764 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000765#else
766 ret = xmlStrcat(ret, xmlBufferContent(node->content));
767#endif
768 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000769 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000770 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000771 buf[0] = '&'; buf[1] = 0;
772 ret = xmlStrncat(ret, buf, 1);
773 ret = xmlStrcat(ret, node->name);
774 buf[0] = ';'; buf[1] = 0;
775 ret = xmlStrncat(ret, buf, 1);
776 }
777 }
778#if 0
779 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000780 xmlGenericError(xmlGenericErrorContext,
781 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardccb09631998-10-27 06:21:04 +0000782 node->type);
783 }
784#endif
785 node = node->next;
786 }
787 return(ret);
788}
789
790/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000791 * xmlNodeListGetRawString:
792 * @doc: the document
793 * @list: a Node list
794 * @inLine: should we replace entity contents or show their external form
795 *
796 * Returns the string equivalent to the text contained in the Node list
797 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
798 * this function doesn't do any character encoding handling.
799 *
800 * Returns a pointer to the string copy, the calller must free it.
801 */
802xmlChar *
803xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
804 xmlNodePtr node = list;
805 xmlChar *ret = NULL;
806 xmlEntityPtr ent;
807
808 if (list == NULL) return(NULL);
809
810 while (node != NULL) {
811 if (node->type == XML_TEXT_NODE) {
812 if (inLine) {
813#ifndef XML_USE_BUFFER_CONTENT
814 ret = xmlStrcat(ret, node->content);
815#else
816 ret = xmlStrcat(ret, xmlBufferContent(node->content));
817#endif
818 } else {
819 xmlChar *buffer;
820
821#ifndef XML_USE_BUFFER_CONTENT
822 buffer = xmlEncodeSpecialChars(doc, node->content);
823#else
824 buffer = xmlEncodeSpecialChars(doc,
825 xmlBufferContent(node->content));
826#endif
827 if (buffer != NULL) {
828 ret = xmlStrcat(ret, buffer);
829 xmlFree(buffer);
830 }
831 }
832 } else if (node->type == XML_ENTITY_REF_NODE) {
833 if (inLine) {
834 ent = xmlGetDocEntity(doc, node->name);
835 if (ent != NULL)
836 ret = xmlStrcat(ret, ent->content);
837 else {
838#ifndef XML_USE_BUFFER_CONTENT
839 ret = xmlStrcat(ret, node->content);
840#else
841 ret = xmlStrcat(ret, xmlBufferContent(node->content));
842#endif
843 }
844 } else {
845 xmlChar buf[2];
846 buf[0] = '&'; buf[1] = 0;
847 ret = xmlStrncat(ret, buf, 1);
848 ret = xmlStrcat(ret, node->name);
849 buf[0] = ';'; buf[1] = 0;
850 ret = xmlStrncat(ret, buf, 1);
851 }
852 }
853#if 0
854 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000855 xmlGenericError(xmlGenericErrorContext,
856 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardbe803962000-06-28 23:40:59 +0000857 node->type);
858 }
859#endif
860 node = node->next;
861 }
862 return(ret);
863}
864
865/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000866 * xmlNewProp:
867 * @node: the holding node
868 * @name: the name of the attribute
869 * @value: the value of the attribute
870 *
871 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000872 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000873 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000874xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000875xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000876 xmlAttrPtr cur;
877
878 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000879#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000880 xmlGenericError(xmlGenericErrorContext,
881 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000882#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000883 return(NULL);
884 }
885
886 /*
887 * Allocate a new property and fill the fields.
888 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000889 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000890 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000891 xmlGenericError(xmlGenericErrorContext,
892 "xmlNewProp : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000893 return(NULL);
894 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000895 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000896 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000897
898 cur->parent = node;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000899 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000900 if (value != NULL) {
901 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000902 xmlNodePtr tmp;
903
Daniel Veillard51e3b151999-11-12 17:02:31 +0000904 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +0000905 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000906 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000907 tmp = cur->children;
908 while (tmp != NULL) {
909 tmp->parent = (xmlNodePtr) cur;
910 if (tmp->next == NULL)
911 cur->last = tmp;
912 tmp = tmp->next;
913 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000914 xmlFree(buffer);
915 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000916
917 /*
918 * Add it at the end to preserve parsing order ...
919 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000920 if (node != NULL) {
921 if (node->properties == NULL) {
922 node->properties = cur;
923 } else {
924 xmlAttrPtr prev = node->properties;
925
926 while (prev->next != NULL) prev = prev->next;
927 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000928 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000929 }
930 }
931 return(cur);
932}
933
934/**
935 * xmlNewNsProp:
936 * @node: the holding node
937 * @ns: the namespace
938 * @name: the name of the attribute
939 * @value: the value of the attribute
940 *
941 * Create a new property tagged with a namespace and carried by a node.
942 * Returns a pointer to the attribute
943 */
944xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000945xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
946 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000947 xmlAttrPtr cur;
948
949 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000950#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000951 xmlGenericError(xmlGenericErrorContext,
952 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000953#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +0000954 return(NULL);
955 }
956
957 /*
958 * Allocate a new property and fill the fields.
959 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000960 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000961 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000962 xmlGenericError(xmlGenericErrorContext,
963 "xmlNewProp : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000964 return(NULL);
965 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000966 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000967 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000968
969 cur->parent = node;
970 if (node != NULL)
971 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000972 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000973 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +0000974 if (value != NULL) {
975 xmlChar *buffer;
976 xmlNodePtr tmp;
977
978 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
979 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000980 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000981 tmp = cur->children;
982 while (tmp != NULL) {
983 tmp->parent = (xmlNodePtr) cur;
984 if (tmp->next == NULL)
985 cur->last = tmp;
986 tmp = tmp->next;
987 }
988 xmlFree(buffer);
989 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000990
991 /*
992 * Add it at the end to preserve parsing order ...
993 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000994 if (node != NULL) {
995 if (node->properties == NULL) {
996 node->properties = cur;
997 } else {
998 xmlAttrPtr prev = node->properties;
999
1000 while (prev->next != NULL) prev = prev->next;
1001 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001002 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001003 }
1004 }
1005 return(cur);
1006}
1007
Daniel Veillard97b58771998-10-20 06:14:16 +00001008/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001009 * xmlNewDocProp:
1010 * @doc: the document
1011 * @name: the name of the attribute
1012 * @value: the value of the attribute
1013 *
1014 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001015 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001016 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001017xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001018xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001019 xmlAttrPtr cur;
1020
1021 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001022#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001023 xmlGenericError(xmlGenericErrorContext,
1024 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001025#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001026 return(NULL);
1027 }
1028
1029 /*
1030 * Allocate a new property and fill the fields.
1031 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001032 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001033 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001034 xmlGenericError(xmlGenericErrorContext,
1035 "xmlNewProp : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001036 return(NULL);
1037 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001038 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001039 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001040
Daniel Veillardcf461992000-03-14 18:30:20 +00001041 cur->name = xmlStrdup(name);
1042 cur->doc = doc;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001043 if (value != NULL) {
1044 xmlNodePtr tmp;
1045
Daniel Veillardcf461992000-03-14 18:30:20 +00001046 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001047 cur->last = NULL;
1048
1049 tmp = cur->children;
1050 while (tmp != NULL) {
1051 tmp->parent = (xmlNodePtr) cur;
1052 if (tmp->next == NULL)
1053 cur->last = tmp;
1054 tmp = tmp->next;
1055 }
1056 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001057 return(cur);
1058}
1059
1060/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001061 * xmlFreePropList:
1062 * @cur: the first property in the list
1063 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001064 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001065 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001066void
1067xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001068 xmlAttrPtr next;
1069 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001070#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001071 xmlGenericError(xmlGenericErrorContext,
1072 "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001073#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001074 return;
1075 }
1076 while (cur != NULL) {
1077 next = cur->next;
1078 xmlFreeProp(cur);
1079 cur = next;
1080 }
1081}
1082
Daniel Veillard97b58771998-10-20 06:14:16 +00001083/**
1084 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001085 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001086 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001087 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001088 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001089void
1090xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001091 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001092#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001093 xmlGenericError(xmlGenericErrorContext,
1094 "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001095#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001096 return;
1097 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001098 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001099 if ((cur->parent != NULL) &&
1100 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1101 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001102 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001103 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001104 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001105 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001106}
1107
Daniel Veillard97b58771998-10-20 06:14:16 +00001108/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001109 * xmlRemoveProp:
1110 * @cur: an attribute
1111 *
1112 * Unlink and free one attribute, all the content is freed too
1113 * Note this doesn't work for namespace definition attributes
1114 *
1115 * Returns 0 if success and -1 in case of error.
1116 */
1117int
1118xmlRemoveProp(xmlAttrPtr cur) {
1119 xmlAttrPtr tmp;
1120 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001121#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001122 xmlGenericError(xmlGenericErrorContext,
1123 "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001124#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001125 return(-1);
1126 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001127 if (cur->parent == NULL) {
1128#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001129 xmlGenericError(xmlGenericErrorContext,
1130 "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001131#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001132 return(-1);
1133 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001134 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001135 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001136 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001137 xmlFreeProp(cur);
1138 return(0);
1139 }
1140 while (tmp != NULL) {
1141 if (tmp->next == cur) {
1142 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001143 if (tmp->next != NULL)
1144 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001145 xmlFreeProp(cur);
1146 return(0);
1147 }
1148 tmp = tmp->next;
1149 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001150#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001151 xmlGenericError(xmlGenericErrorContext,
1152 "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001153#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001154 return(-1);
1155}
1156
1157/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001158 * xmlNewPI:
1159 * @name: the processing instruction name
1160 * @content: the PI content
1161 *
1162 * Creation of a processing instruction element.
1163 * Returns a pointer to the new node object.
1164 */
1165xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001166xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001167 xmlNodePtr cur;
1168
1169 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001170#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001171 xmlGenericError(xmlGenericErrorContext,
1172 "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001173#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001174 return(NULL);
1175 }
1176
1177 /*
1178 * Allocate a new node and fill the fields.
1179 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001180 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001181 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001182 xmlGenericError(xmlGenericErrorContext,
1183 "xmlNewPI : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001184 return(NULL);
1185 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001186 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001187 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001188
Daniel Veillardb96e6431999-08-29 21:02:19 +00001189 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001190 if (content != NULL) {
1191#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001192 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001193#else
1194 cur->content = xmlBufferCreateSize(0);
1195 xmlBufferSetAllocationScheme(cur->content,
1196 xmlGetBufferAllocationScheme());
1197 xmlBufferAdd(cur->content, content, -1);
1198#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001199 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001200 return(cur);
1201}
1202
1203/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001204 * xmlNewNode:
1205 * @ns: namespace if any
1206 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001207 *
Daniel Veillarde0854c32000-08-27 21:12:29 +00001208 * Creation of a new node element. @ns is optionnal (NULL).
1209 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001210 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001211 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001212xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001213xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001214 xmlNodePtr cur;
1215
1216 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001217#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001218 xmlGenericError(xmlGenericErrorContext,
1219 "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001220#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001221 return(NULL);
1222 }
1223
1224 /*
1225 * Allocate a new node and fill the fields.
1226 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001227 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001228 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001229 xmlGenericError(xmlGenericErrorContext,
1230 "xmlNewNode : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001231 return(NULL);
1232 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001233 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001234 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001235
Daniel Veillard260a68f1998-08-13 03:39:55 +00001236 cur->name = xmlStrdup(name);
1237 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001238 return(cur);
1239}
1240
Daniel Veillard97b58771998-10-20 06:14:16 +00001241/**
1242 * xmlNewDocNode:
1243 * @doc: the document
1244 * @ns: namespace if any
1245 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001246 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001247 *
1248 * Creation of a new node element within a document. @ns and @content
1249 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001250 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1251 * references, but XML special chars need to be escaped first by using
1252 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1253 * need entities support.
1254 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001255 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001256 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001257xmlNodePtr
1258xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001259 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001260 xmlNodePtr cur;
1261
Daniel Veillardccb09631998-10-27 06:21:04 +00001262 cur = xmlNewNode(ns, name);
1263 if (cur != NULL) {
1264 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001265 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001266 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001267 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001268 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001269 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001270 return(cur);
1271}
1272
1273
Daniel Veillard97b58771998-10-20 06:14:16 +00001274/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001275 * xmlNewDocRawNode:
1276 * @doc: the document
1277 * @ns: namespace if any
1278 * @name: the node name
1279 * @content: the text content if any
1280 *
1281 * Creation of a new node element within a document. @ns and @content
1282 * are optionnal (NULL).
1283 *
1284 * Returns a pointer to the new node object.
1285 */
1286xmlNodePtr
1287xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1288 const xmlChar *name, const xmlChar *content) {
1289 xmlNodePtr cur;
1290
1291 cur = xmlNewNode(ns, name);
1292 if (cur != NULL) {
1293 cur->doc = doc;
1294 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001295 cur->children = xmlNewDocText(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001296 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001297 }
1298 }
1299 return(cur);
1300}
1301
Daniel Veillard2eac5032000-01-09 21:08:56 +00001302/**
1303 * xmlNewDocFragment:
1304 * @doc: the document owning the fragment
1305 *
1306 * Creation of a new Fragment node.
1307 * Returns a pointer to the new node object.
1308 */
1309xmlNodePtr
1310xmlNewDocFragment(xmlDocPtr doc) {
1311 xmlNodePtr cur;
1312
1313 /*
1314 * Allocate a new DocumentFragment node and fill the fields.
1315 */
1316 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1317 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001318 xmlGenericError(xmlGenericErrorContext,
1319 "xmlNewDocFragment : malloc failed\n");
Daniel Veillard2eac5032000-01-09 21:08:56 +00001320 return(NULL);
1321 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001322 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001323 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001324
Daniel Veillard2eac5032000-01-09 21:08:56 +00001325 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001326 return(cur);
1327}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001328
1329/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001330 * xmlNewText:
1331 * @content: the text content
1332 *
1333 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001334 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001335 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001336xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001337xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001338 xmlNodePtr cur;
1339
1340 /*
1341 * Allocate a new node and fill the fields.
1342 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001343 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001344 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001345 xmlGenericError(xmlGenericErrorContext,
1346 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001347 return(NULL);
1348 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001349 memset(cur, 0, sizeof(xmlNode));
1350 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001351
Daniel Veillardf6eea272001-01-18 12:17:12 +00001352 cur->name = xmlStringText;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001353 if (content != NULL) {
1354#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001355 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001356#else
1357 cur->content = xmlBufferCreateSize(0);
1358 xmlBufferSetAllocationScheme(cur->content,
1359 xmlGetBufferAllocationScheme());
1360 xmlBufferAdd(cur->content, content, -1);
1361#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001362 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001363 return(cur);
1364}
1365
Daniel Veillard97b58771998-10-20 06:14:16 +00001366/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001367 * xmlNewTextChild:
1368 * @parent: the parent node
1369 * @ns: a namespace if any
1370 * @name: the name of the child
1371 * @content: the text content of the child if any.
1372 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001373 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001374 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1375 * a child TEXT node will be created containing the string content.
1376 *
1377 * Returns a pointer to the new node object.
1378 */
1379xmlNodePtr
1380xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1381 const xmlChar *name, const xmlChar *content) {
1382 xmlNodePtr cur, prev;
1383
1384 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001385#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001386 xmlGenericError(xmlGenericErrorContext,
1387 "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001388#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001389 return(NULL);
1390 }
1391
1392 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001393#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001394 xmlGenericError(xmlGenericErrorContext,
1395 "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001396#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001397 return(NULL);
1398 }
1399
1400 /*
1401 * Allocate a new node
1402 */
1403 if (ns == NULL)
1404 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1405 else
1406 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1407 if (cur == NULL) return(NULL);
1408
1409 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001410 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001411 */
1412 cur->type = XML_ELEMENT_NODE;
1413 cur->parent = parent;
1414 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001415 if (parent->children == NULL) {
1416 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001417 parent->last = cur;
1418 } else {
1419 prev = parent->last;
1420 prev->next = cur;
1421 cur->prev = prev;
1422 parent->last = cur;
1423 }
1424
1425 return(cur);
1426}
1427
1428/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001429 * xmlNewCharRef:
1430 * @doc: the document
1431 * @name: the char ref string, starting with # or "&# ... ;"
1432 *
1433 * Creation of a new character reference node.
1434 * Returns a pointer to the new node object.
1435 */
1436xmlNodePtr
1437xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1438 xmlNodePtr cur;
1439
1440 /*
1441 * Allocate a new node and fill the fields.
1442 */
1443 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1444 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001445 xmlGenericError(xmlGenericErrorContext,
1446 "xmlNewText : malloc failed\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001447 return(NULL);
1448 }
1449 memset(cur, 0, sizeof(xmlNode));
1450 cur->type = XML_ENTITY_REF_NODE;
1451
1452 cur->doc = doc;
1453 if (name[0] == '&') {
1454 int len;
1455 name++;
1456 len = xmlStrlen(name);
1457 if (name[len - 1] == ';')
1458 cur->name = xmlStrndup(name, len - 1);
1459 else
1460 cur->name = xmlStrndup(name, len);
1461 } else
1462 cur->name = xmlStrdup(name);
1463 return(cur);
1464}
1465
1466/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001467 * xmlNewReference:
1468 * @doc: the document
1469 * @name: the reference name, or the reference string with & and ;
1470 *
1471 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001472 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001473 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001474xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001475xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001476 xmlNodePtr cur;
1477 xmlEntityPtr ent;
1478
1479 /*
1480 * Allocate a new node and fill the fields.
1481 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001482 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001483 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlNewText : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001486 return(NULL);
1487 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001488 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001489 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001490
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001491 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001492 if (name[0] == '&') {
1493 int len;
1494 name++;
1495 len = xmlStrlen(name);
1496 if (name[len - 1] == ';')
1497 cur->name = xmlStrndup(name, len - 1);
1498 else
1499 cur->name = xmlStrndup(name, len);
1500 } else
1501 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001502
1503 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001504 if (ent != NULL) {
1505#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001506 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001507#else
1508 /*
1509 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1510 * a copy of this pointer. Let's hope we don't manipulate it
1511 * later
1512 */
1513 cur->content = xmlBufferCreateSize(0);
1514 xmlBufferSetAllocationScheme(cur->content,
1515 xmlGetBufferAllocationScheme());
1516 if (ent->content != NULL)
1517 xmlBufferAdd(cur->content, ent->content, -1);
1518#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001519 /*
1520 * The parent pointer in entity is a Dtd pointer and thus is NOT
1521 * updated. Not sure if this is 100% correct.
1522 * -George
1523 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001524 cur->children = (xmlNodePtr) ent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001525 cur->last = (xmlNodePtr) ent;
Daniel Veillardcf461992000-03-14 18:30:20 +00001526 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001527 return(cur);
1528}
1529
1530/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001531 * xmlNewDocText:
1532 * @doc: the document
1533 * @content: the text content
1534 *
1535 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001536 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001537 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001538xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001539xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001540 xmlNodePtr cur;
1541
1542 cur = xmlNewText(content);
1543 if (cur != NULL) cur->doc = doc;
1544 return(cur);
1545}
1546
Daniel Veillard97b58771998-10-20 06:14:16 +00001547/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001548 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001549 * @content: the text content
1550 * @len: the text len.
1551 *
1552 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001553 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001554 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001555xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001556xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001557 xmlNodePtr cur;
1558
1559 /*
1560 * Allocate a new node and fill the fields.
1561 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001562 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001563 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001564 xmlGenericError(xmlGenericErrorContext,
1565 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001566 return(NULL);
1567 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001568 memset(cur, 0, sizeof(xmlNode));
1569 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001570
Daniel Veillardf6eea272001-01-18 12:17:12 +00001571 cur->name = xmlStringText;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001572 if (content != NULL) {
1573#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001574 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001575#else
1576 cur->content = xmlBufferCreateSize(len);
1577 xmlBufferSetAllocationScheme(cur->content,
1578 xmlGetBufferAllocationScheme());
1579 xmlBufferAdd(cur->content, content, len);
1580#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001581 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001582 return(cur);
1583}
1584
Daniel Veillard97b58771998-10-20 06:14:16 +00001585/**
1586 * xmlNewDocTextLen:
1587 * @doc: the document
1588 * @content: the text content
1589 * @len: the text len.
1590 *
1591 * Creation of a new text node with an extra content lenght parameter. The
1592 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001593 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001594 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001595xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001596xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001597 xmlNodePtr cur;
1598
1599 cur = xmlNewTextLen(content, len);
1600 if (cur != NULL) cur->doc = doc;
1601 return(cur);
1602}
1603
Daniel Veillard97b58771998-10-20 06:14:16 +00001604/**
1605 * xmlNewComment:
1606 * @content: the comment content
1607 *
1608 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001609 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001610 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001611xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001612xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001613 xmlNodePtr cur;
1614
1615 /*
1616 * Allocate a new node and fill the fields.
1617 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001618 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001619 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001620 xmlGenericError(xmlGenericErrorContext,
1621 "xmlNewComment : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001622 return(NULL);
1623 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001624 memset(cur, 0, sizeof(xmlNode));
1625 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001626
Daniel Veillardf6eea272001-01-18 12:17:12 +00001627 cur->name = xmlStringComment;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001628 if (content != NULL) {
1629#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001630 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001631#else
1632 cur->content = xmlBufferCreateSize(0);
1633 xmlBufferSetAllocationScheme(cur->content,
1634 xmlGetBufferAllocationScheme());
1635 xmlBufferAdd(cur->content, content, -1);
1636#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001637 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001638 return(cur);
1639}
1640
Daniel Veillard97b58771998-10-20 06:14:16 +00001641/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001642 * xmlNewCDataBlock:
1643 * @doc: the document
1644 * @content: the CData block content content
1645 * @len: the length of the block
1646 *
1647 * Creation of a new node containing a CData block.
1648 * Returns a pointer to the new node object.
1649 */
1650xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001651xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001652 xmlNodePtr cur;
1653
1654 /*
1655 * Allocate a new node and fill the fields.
1656 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001657 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001658 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001659 xmlGenericError(xmlGenericErrorContext,
1660 "xmlNewCDataBlock : malloc failed\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001661 return(NULL);
1662 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001663 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001664 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001665
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001666 if (content != NULL) {
1667#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001668 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001669#else
1670 cur->content = xmlBufferCreateSize(len);
1671 xmlBufferSetAllocationScheme(cur->content,
1672 xmlGetBufferAllocationScheme());
1673 xmlBufferAdd(cur->content, content, len);
1674#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001675 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001676 return(cur);
1677}
1678
1679/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001680 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001681 * @doc: the document
1682 * @content: the comment content
1683 *
1684 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001685 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001686 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001687xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001688xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001689 xmlNodePtr cur;
1690
1691 cur = xmlNewComment(content);
1692 if (cur != NULL) cur->doc = doc;
1693 return(cur);
1694}
1695
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001696/**
1697 * xmlSetTreeDoc:
1698 * @tree: the top element
1699 * @doc: the document
1700 *
1701 * update all nodes under the tree to point to the right document
1702 */
1703void
1704xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1705 if (tree == NULL)
1706 return;
1707 if (tree->type == XML_ENTITY_DECL)
1708 return;
1709 if (tree->doc != doc) {
1710 if (tree->children != NULL)
1711 xmlSetListDoc(tree->children, doc);
1712 tree->doc = doc;
1713 }
1714}
1715
1716/**
1717 * xmlSetListDoc:
1718 * @tree: the first element
1719 * @doc: the document
1720 *
1721 * update all nodes in the list to point to the right document
1722 */
1723void
1724xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1725 xmlNodePtr cur;
1726
1727 if (list == NULL)
1728 return;
1729 cur = list;
1730 while (cur != NULL) {
1731 if (cur->doc != doc)
1732 xmlSetTreeDoc(cur, doc);
1733 cur = cur->next;
1734 }
1735}
1736
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001737
Daniel Veillard97b58771998-10-20 06:14:16 +00001738/**
1739 * xmlNewChild:
1740 * @parent: the parent node
1741 * @ns: a namespace if any
1742 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001743 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001744 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001745 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001746 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1747 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001748 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1749 * references, but XML special chars need to be escaped first by using
1750 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1751 * support is not needed.
1752 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001753 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001754 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001755xmlNodePtr
1756xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001757 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001758 xmlNodePtr cur, prev;
1759
1760 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001761#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001762 xmlGenericError(xmlGenericErrorContext,
1763 "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001764#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001765 return(NULL);
1766 }
1767
1768 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001769#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001772#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001773 return(NULL);
1774 }
1775
1776 /*
1777 * Allocate a new node
1778 */
1779 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001780 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001781 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001782 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001783 if (cur == NULL) return(NULL);
1784
1785 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001786 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001787 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001788 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001789 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001790 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001791 if (parent->children == NULL) {
1792 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001793 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001794 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001795 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001796 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001797 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001798 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001799 }
1800
1801 return(cur);
1802}
1803
Daniel Veillard97b58771998-10-20 06:14:16 +00001804/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001805 * xmlAddNextSibling:
1806 * @cur: the child node
1807 * @elem: the new node
1808 *
1809 * Add a new element @elem as the next siblings of @cur
1810 * If the new element was already inserted in a document it is
1811 * first unlinked from its existing context.
Daniel Veillard683cb022000-10-22 12:04:13 +00001812 * As a result of text merging @elem may be freed.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001813 *
1814 * Returns the new element or NULL in case of error.
1815 */
1816xmlNodePtr
1817xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1818 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001819#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001820 xmlGenericError(xmlGenericErrorContext,
1821 "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001822#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001823 return(NULL);
1824 }
1825 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001826#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001827 xmlGenericError(xmlGenericErrorContext,
1828 "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001829#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001830 return(NULL);
1831 }
1832
1833 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001834
1835 if (elem->type == XML_TEXT_NODE) {
1836 if (cur->type == XML_TEXT_NODE) {
1837#ifndef XML_USE_BUFFER_CONTENT
1838 xmlNodeAddContent(cur, elem->content);
1839#else
1840 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1841#endif
1842 xmlFreeNode(elem);
1843 return(cur);
1844 }
1845 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1846#ifndef XML_USE_BUFFER_CONTENT
1847 xmlChar *tmp;
1848
1849 tmp = xmlStrdup(elem->content);
1850 tmp = xmlStrcat(tmp, cur->next->content);
1851 xmlNodeSetContent(cur->next, tmp);
1852 xmlFree(tmp);
1853#else
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001854 xmlBufferAddHead(cur->next->content,
1855 xmlBufferContent(elem->content),
Daniel Veillard683cb022000-10-22 12:04:13 +00001856 xmlBufferLength(elem->content));
1857#endif
1858 xmlFreeNode(elem);
1859 return(cur->next);
1860 }
1861 }
1862
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001863 if (elem->doc != cur->doc) {
1864 xmlSetTreeDoc(elem, cur->doc);
1865 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001866 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001867 elem->prev = cur;
1868 elem->next = cur->next;
1869 cur->next = elem;
1870 if (elem->next != NULL)
1871 elem->next->prev = elem;
1872 if ((elem->parent != NULL) && (elem->parent->last == cur))
1873 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001874 return(elem);
1875}
1876
1877/**
1878 * xmlAddPrevSibling:
1879 * @cur: the child node
1880 * @elem: the new node
1881 *
1882 * Add a new element @elem as the previous siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001883 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001884 * If the new element was already inserted in a document it is
1885 * first unlinked from its existing context.
1886 *
1887 * Returns the new element or NULL in case of error.
1888 */
1889xmlNodePtr
1890xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1891 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001892#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlAddPrevSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001895#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001896 return(NULL);
1897 }
1898 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001899#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001900 xmlGenericError(xmlGenericErrorContext,
1901 "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001902#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001903 return(NULL);
1904 }
1905
1906 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001907
1908 if (elem->type == XML_TEXT_NODE) {
1909 if (cur->type == XML_TEXT_NODE) {
1910#ifndef XML_USE_BUFFER_CONTENT
1911 xmlChar *tmp;
1912
1913 tmp = xmlStrdup(elem->content);
1914 tmp = xmlStrcat(tmp, cur->content);
1915 xmlNodeSetContent(cur, tmp);
1916 xmlFree(tmp);
1917#else
1918 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1919 xmlBufferLength(elem->content));
1920#endif
1921 xmlFreeNode(elem);
1922 return(cur);
1923 }
1924 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1925#ifndef XML_USE_BUFFER_CONTENT
1926 xmlNodeAddContent(cur->prev, elem->content);
1927#else
1928 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1929#endif
1930 xmlFreeNode(elem);
1931 return(cur->prev);
1932 }
1933 }
1934
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001935 if (elem->doc != cur->doc) {
1936 xmlSetTreeDoc(elem, cur->doc);
1937 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001938 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001939 elem->next = cur;
1940 elem->prev = cur->prev;
1941 cur->prev = elem;
1942 if (elem->prev != NULL)
1943 elem->prev->next = elem;
1944 if ((elem->parent != NULL) && (elem->parent->children == cur))
1945 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001946 return(elem);
1947}
1948
1949/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001950 * xmlAddSibling:
1951 * @cur: the child node
1952 * @elem: the new node
1953 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001954 * Add a new element @elem to the list of siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001955 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001956 * If the new element was already inserted in a document it is
1957 * first unlinked from its existing context.
1958 *
1959 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001960 */
1961xmlNodePtr
1962xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1963 xmlNodePtr parent;
1964
1965 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001966#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001967 xmlGenericError(xmlGenericErrorContext,
1968 "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001969#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001970 return(NULL);
1971 }
1972
1973 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001974#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001975 xmlGenericError(xmlGenericErrorContext,
1976 "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001977#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001978 return(NULL);
1979 }
1980
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001981 /*
1982 * Constant time is we can rely on the ->parent->last to find
1983 * the last sibling.
1984 */
1985 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001986 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001987 (cur->parent->last != NULL) &&
1988 (cur->parent->last->next == NULL)) {
1989 cur = cur->parent->last;
1990 } else {
1991 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001992 }
1993
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001994 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001995
1996 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
1997#ifndef XML_USE_BUFFER_CONTENT
1998 xmlNodeAddContent(cur, elem->content);
1999#else
2000 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2001#endif
2002 xmlFreeNode(elem);
2003 return(cur);
2004 }
2005
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002006 if (elem->doc != cur->doc) {
2007 xmlSetTreeDoc(elem, cur->doc);
2008 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002009 parent = cur->parent;
2010 elem->prev = cur;
2011 elem->next = NULL;
2012 elem->parent = parent;
2013 cur->next = elem;
2014 if (parent != NULL)
2015 parent->last = elem;
2016
2017 return(elem);
2018}
2019
2020/**
Daniel Veillard87b95392000-08-12 21:12:04 +00002021 * xmlAddChildList:
2022 * @parent: the parent node
2023 * @cur: the first node in the list
2024 *
2025 * Add a list of node at the end of the child list of the parent
Daniel Veillard683cb022000-10-22 12:04:13 +00002026 * merging adjacent TEXT nodes (@cur may be freed)
Daniel Veillard87b95392000-08-12 21:12:04 +00002027 *
2028 * Returns the last child or NULL in case of error.
2029 */
2030xmlNodePtr
2031xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2032 xmlNodePtr prev;
2033
2034 if (parent == NULL) {
2035#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002036 xmlGenericError(xmlGenericErrorContext,
2037 "xmlAddChild : parent == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002038#endif
2039 return(NULL);
2040 }
2041
2042 if (cur == NULL) {
2043#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002044 xmlGenericError(xmlGenericErrorContext,
2045 "xmlAddChild : child == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002046#endif
2047 return(NULL);
2048 }
2049
2050 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2051 (cur->doc != parent->doc)) {
2052#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002053 xmlGenericError(xmlGenericErrorContext,
2054 "Elements moved to a different document\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002055#endif
2056 }
2057
2058 /*
2059 * add the first element at the end of the children list.
2060 */
2061 if (parent->children == NULL) {
2062 parent->children = cur;
2063 } else {
Daniel Veillard683cb022000-10-22 12:04:13 +00002064 /*
2065 * If cur and parent->last both are TEXT nodes, then merge them.
2066 */
2067 if ((cur->type == XML_TEXT_NODE) &&
2068 (parent->last->type == XML_TEXT_NODE)) {
2069#ifndef XML_USE_BUFFER_CONTENT
2070 xmlNodeAddContent(parent->last, cur->content);
2071#else
2072 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2073#endif
2074 /*
2075 * if it's the only child, nothing more to be done.
2076 */
2077 if (cur->next == NULL) {
2078 xmlFreeNode(cur);
2079 return(parent->last);
2080 }
2081 prev = cur;
2082 cur = cur->next;
2083 xmlFreeNode(prev);
2084 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002085 prev = parent->last;
2086 prev->next = cur;
2087 cur->prev = prev;
2088 }
2089 while (cur->next != NULL) {
2090 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002091 if (cur->doc != parent->doc) {
2092 xmlSetTreeDoc(cur, parent->doc);
2093 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002094 cur = cur->next;
2095 }
2096 cur->parent = parent;
2097 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2098 parent->last = cur;
2099
2100 return(cur);
2101}
2102
2103/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002104 * xmlAddChild:
2105 * @parent: the parent node
2106 * @cur: the child node
2107 *
Daniel Veillard683cb022000-10-22 12:04:13 +00002108 * Add a new child element, to @parent, at the end of the child list
2109 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillard1e346af1999-02-22 10:33:01 +00002110 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002111 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002112xmlNodePtr
2113xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002114 xmlNodePtr prev;
2115
2116 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002117#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002120#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002121 return(NULL);
2122 }
2123
2124 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002125#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002126 xmlGenericError(xmlGenericErrorContext,
2127 "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002128#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002129 return(NULL);
2130 }
2131
Daniel Veillard0bef1311998-10-14 02:36:47 +00002132 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2133 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002134#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002135 xmlGenericError(xmlGenericErrorContext,
2136 "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002137#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002138 }
2139
Daniel Veillard260a68f1998-08-13 03:39:55 +00002140 /*
Daniel Veillard683cb022000-10-22 12:04:13 +00002141 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2142 * or with parent->content if parent->content != NULL.
2143 * cur is then freed.
2144 */
2145 if (cur->type == XML_TEXT_NODE) {
2146 if (((parent->type == XML_ELEMENT_NODE) ||
2147 (parent->type == XML_TEXT_NODE)) &&
2148 (parent->content != NULL)) {
2149#ifndef XML_USE_BUFFER_CONTENT
2150 xmlNodeAddContent(parent, cur->content);
2151#else
2152 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2153#endif
2154 xmlFreeNode(cur);
2155 return(parent);
2156 }
2157 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE)) {
2158#ifndef XML_USE_BUFFER_CONTENT
2159 xmlNodeAddContent(parent->last, cur->content);
2160#else
2161 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2162#endif
2163 xmlFreeNode(cur);
2164 return(parent->last);
2165 }
2166 }
2167
2168 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002169 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002170 */
2171 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002172 if (cur->doc != parent->doc) {
2173 xmlSetTreeDoc(cur, parent->doc);
2174 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002175
Daniel Veillardccb09631998-10-27 06:21:04 +00002176 /*
2177 * Handle the case where parent->content != NULL, in that case it will
2178 * create a intermediate TEXT node.
2179 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002180 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2181 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002182 xmlNodePtr text;
2183
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002184#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002185 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002186#else
2187 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2188#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002189 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002190 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002191 if (text->next != NULL)
2192 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002193 parent->children = text;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002194 UPDATE_LAST_CHILD_AND_PARENT(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002195#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002196 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002197#else
2198 xmlBufferFree(parent->content);
2199#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002200 parent->content = NULL;
2201 }
2202 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002203 if (parent->children == NULL) {
2204 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002205 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002206 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002207 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002208 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002209 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002210 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002211 }
2212
2213 return(cur);
2214}
2215
Daniel Veillard97b58771998-10-20 06:14:16 +00002216/**
2217 * xmlGetLastChild:
2218 * @parent: the parent node
2219 *
2220 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002221 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002222 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002223xmlNodePtr
2224xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002225 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002226#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002227 xmlGenericError(xmlGenericErrorContext,
2228 "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002229#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002230 return(NULL);
2231 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002232 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002233}
2234
Daniel Veillard97b58771998-10-20 06:14:16 +00002235/**
2236 * xmlFreeNodeList:
2237 * @cur: the first node in the list
2238 *
2239 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002240 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002241 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002242void
2243xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002244 xmlNodePtr next;
2245 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002246#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002247 xmlGenericError(xmlGenericErrorContext,
2248 "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002249#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002250 return;
2251 }
2252 while (cur != NULL) {
2253 next = cur->next;
2254 xmlFreeNode(cur);
2255 cur = next;
2256 }
2257}
2258
Daniel Veillard97b58771998-10-20 06:14:16 +00002259/**
2260 * xmlFreeNode:
2261 * @cur: the node
2262 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002263 * Free a node, this is a recursive behaviour, all the children are freed too.
2264 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002265 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002266void
2267xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002268 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002269#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002270 xmlGenericError(xmlGenericErrorContext,
2271 "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002272#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002273 return;
2274 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002275 if (cur->type == XML_DTD_NODE)
2276 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002277 cur->doc = NULL;
2278 cur->parent = NULL;
2279 cur->next = NULL;
2280 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002281 if ((cur->children != NULL) &&
2282 (cur->type != XML_ENTITY_REF_NODE))
2283 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002284 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2285 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002286#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002287 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002288#else
2289 if (cur->content != NULL) xmlBufferFree(cur->content);
2290#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00002291 if ((cur->name != NULL) &&
2292 (cur->name != xmlStringText) &&
2293 (cur->name != xmlStringTextNoenc) &&
2294 (cur->name != xmlStringComment))
2295 xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002296 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2297 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002298 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002299}
2300
Daniel Veillard16253641998-10-28 22:58:05 +00002301/**
2302 * xmlUnlinkNode:
2303 * @cur: the node
2304 *
2305 * Unlink a node from it's current context, the node is not freed
2306 */
2307void
2308xmlUnlinkNode(xmlNodePtr cur) {
2309 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002310#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002311 xmlGenericError(xmlGenericErrorContext,
2312 "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002313#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002314 return;
2315 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002316 if ((cur->parent != NULL) && (cur->parent->children == cur))
2317 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002318 if ((cur->parent != NULL) && (cur->parent->last == cur))
2319 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002320 if (cur->next != NULL)
2321 cur->next->prev = cur->prev;
2322 if (cur->prev != NULL)
2323 cur->prev->next = cur->next;
2324 cur->next = cur->prev = NULL;
2325 cur->parent = NULL;
2326}
2327
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002328/**
2329 * xmlReplaceNode:
2330 * @old: the old node
2331 * @cur: the node
2332 *
2333 * Unlink the old node from it's current context, prune the new one
2334 * at the same place. If cur was already inserted in a document it is
2335 * first unlinked from its existing context.
2336 *
2337 * Returns the old node
2338 */
2339xmlNodePtr
2340xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2341 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002342#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002343 xmlGenericError(xmlGenericErrorContext,
2344 "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002345#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002346 return(NULL);
2347 }
2348 if (cur == NULL) {
2349 xmlUnlinkNode(old);
2350 return(old);
2351 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002352 if (cur == old) {
2353 return(old);
2354 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002355 xmlUnlinkNode(cur);
2356 cur->doc = old->doc;
2357 cur->parent = old->parent;
2358 cur->next = old->next;
2359 if (cur->next != NULL)
2360 cur->next->prev = cur;
2361 cur->prev = old->prev;
2362 if (cur->prev != NULL)
2363 cur->prev->next = cur;
2364 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002365 if (cur->parent->children == old)
2366 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002367 if (cur->parent->last == old)
2368 cur->parent->last = cur;
2369 }
2370 old->next = old->prev = NULL;
2371 old->parent = NULL;
2372 return(old);
2373}
2374
Daniel Veillard260a68f1998-08-13 03:39:55 +00002375/************************************************************************
2376 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002377 * Copy operations *
2378 * *
2379 ************************************************************************/
2380
2381/**
2382 * xmlCopyNamespace:
2383 * @cur: the namespace
2384 *
2385 * Do a copy of the namespace.
2386 *
2387 * Returns: a new xmlNsPtr, or NULL in case of error.
2388 */
2389xmlNsPtr
2390xmlCopyNamespace(xmlNsPtr cur) {
2391 xmlNsPtr ret;
2392
2393 if (cur == NULL) return(NULL);
2394 switch (cur->type) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002395 case XML_LOCAL_NAMESPACE:
2396 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2397 break;
2398 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002399#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002400 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda4964b72000-10-31 18:23:44 +00002401 "xmlCopyNamespace: invalid type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002402#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002403 return(NULL);
2404 }
2405 return(ret);
2406}
2407
2408/**
2409 * xmlCopyNamespaceList:
2410 * @cur: the first namespace
2411 *
2412 * Do a copy of an namespace list.
2413 *
2414 * Returns: a new xmlNsPtr, or NULL in case of error.
2415 */
2416xmlNsPtr
2417xmlCopyNamespaceList(xmlNsPtr cur) {
2418 xmlNsPtr ret = NULL;
2419 xmlNsPtr p = NULL,q;
2420
2421 while (cur != NULL) {
2422 q = xmlCopyNamespace(cur);
2423 if (p == NULL) {
2424 ret = p = q;
2425 } else {
2426 p->next = q;
2427 p = q;
2428 }
2429 cur = cur->next;
2430 }
2431 return(ret);
2432}
2433
Daniel Veillard389e6b72001-01-15 19:41:13 +00002434static xmlNodePtr
2435xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002436/**
2437 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002438 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002439 * @cur: the attribute
2440 *
2441 * Do a copy of the attribute.
2442 *
2443 * Returns: a new xmlAttrPtr, or NULL in case of error.
2444 */
2445xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002446xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002447 xmlAttrPtr ret;
2448
2449 if (cur == NULL) return(NULL);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002450 if (target != NULL)
2451 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2452 else if (cur->parent != NULL)
Daniel Veillardcf461992000-03-14 18:30:20 +00002453 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2454 else if (cur->children != NULL)
2455 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002456 else
2457 ret = xmlNewDocProp(NULL, cur->name, NULL);
2458 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002459 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002460
2461 if ((cur->ns != NULL) && (target != NULL)) {
2462 xmlNsPtr ns;
2463
2464 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2465 ret->ns = ns;
2466 } else
2467 ret->ns = NULL;
2468
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002469 if (cur->children != NULL) {
2470 xmlNodePtr tmp;
2471
Daniel Veillard389e6b72001-01-15 19:41:13 +00002472 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002473 ret->last = NULL;
2474 tmp = ret->children;
2475 while (tmp != NULL) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00002476 /* tmp->parent = (xmlNodePtr)ret; */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002477 if (tmp->next == NULL)
2478 ret->last = tmp;
2479 tmp = tmp->next;
2480 }
2481 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002482 return(ret);
2483}
2484
2485/**
2486 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002487 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002488 * @cur: the first attribute
2489 *
2490 * Do a copy of an attribute list.
2491 *
2492 * Returns: a new xmlAttrPtr, or NULL in case of error.
2493 */
2494xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002495xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002496 xmlAttrPtr ret = NULL;
2497 xmlAttrPtr p = NULL,q;
2498
2499 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002500 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002501 if (p == NULL) {
2502 ret = p = q;
2503 } else {
2504 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002505 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002506 p = q;
2507 }
2508 cur = cur->next;
2509 }
2510 return(ret);
2511}
2512
2513/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002514 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002515 *
2516 * They are splitted into external and internal parts for one
2517 * tricky reason: namespaces. Doing a direct copy of a node
2518 * say RPM:Copyright without changing the namespace pointer to
2519 * something else can produce stale links. One way to do it is
2520 * to keep a reference counter but this doesn't work as soon
2521 * as one move the element or the subtree out of the scope of
2522 * the existing namespace. The actual solution seems to add
2523 * a copy of the namespace at the top of the copied tree if
2524 * not available in the subtree.
2525 * Hence two functions, the public front-end call the inner ones
2526 */
2527
2528static xmlNodePtr
2529xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2530
2531static xmlNodePtr
2532xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2533 int recursive) {
2534 xmlNodePtr ret;
2535
2536 if (node == NULL) return(NULL);
2537 /*
2538 * Allocate a new node and fill the fields.
2539 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002540 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002541 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002542 xmlGenericError(xmlGenericErrorContext,
2543 "xmlStaticCopyNode : malloc failed\n");
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002544 return(NULL);
2545 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002546 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002547 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002548
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002549 ret->doc = doc;
2550 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002551 if (node->name != NULL)
2552 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002553 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2554#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002555 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002556#else
2557 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2558 xmlBufferSetAllocationScheme(ret->content,
2559 xmlGetBufferAllocationScheme());
2560 xmlBufferAdd(ret->content,
2561 xmlBufferContent(node->content),
2562 xmlBufferLength(node->content));
2563#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002564 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002565 if (parent != NULL)
2566 xmlAddChild(parent, ret);
2567
2568 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002569 if (node->nsDef != NULL)
2570 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2571
2572 if (node->ns != NULL) {
2573 xmlNsPtr ns;
2574
2575 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2576 if (ns == NULL) {
2577 /*
2578 * Humm, we are copying an element whose namespace is defined
2579 * out of the new tree scope. Search it in the original tree
2580 * and add it at the top of the new tree
2581 */
2582 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2583 if (ns != NULL) {
2584 xmlNodePtr root = ret;
2585
2586 while (root->parent != NULL) root = root->parent;
2587 xmlNewNs(root, ns->href, ns->prefix);
2588 }
2589 } else {
2590 /*
2591 * reference the existing namespace definition in our own tree.
2592 */
2593 ret->ns = ns;
2594 }
2595 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002596 if (node->properties != NULL)
2597 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002598 if (node->children != NULL)
2599 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002600 UPDATE_LAST_CHILD_AND_PARENT(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002601 return(ret);
2602}
2603
2604static xmlNodePtr
2605xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2606 xmlNodePtr ret = NULL;
2607 xmlNodePtr p = NULL,q;
2608
2609 while (node != NULL) {
2610 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002611 if (ret == NULL) {
2612 q->prev = NULL;
2613 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002614 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002615 p->next = q;
2616 q->prev = p;
2617 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002618 }
2619 node = node->next;
2620 }
2621 return(ret);
2622}
2623
2624/**
2625 * xmlCopyNode:
2626 * @node: the node
2627 * @recursive: if 1 do a recursive copy.
2628 *
2629 * Do a copy of the node.
2630 *
2631 * Returns: a new xmlNodePtr, or NULL in case of error.
2632 */
2633xmlNodePtr
2634xmlCopyNode(xmlNodePtr node, int recursive) {
2635 xmlNodePtr ret;
2636
2637 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2638 return(ret);
2639}
2640
2641/**
2642 * xmlCopyNodeList:
2643 * @node: the first node in the list.
2644 *
2645 * Do a recursive copy of the node list.
2646 *
2647 * Returns: a new xmlNodePtr, or NULL in case of error.
2648 */
2649xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2650 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2651 return(ret);
2652}
2653
2654/**
2655 * xmlCopyElement:
2656 * @elem: the element
2657 *
2658 * Do a copy of the element definition.
2659 *
2660 * Returns: a new xmlElementPtr, or NULL in case of error.
2661xmlElementPtr
2662xmlCopyElement(xmlElementPtr elem) {
2663 xmlElementPtr ret;
2664
2665 if (elem == NULL) return(NULL);
2666 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2667 if (ret == NULL) return(NULL);
2668 if (!recursive) return(ret);
2669 if (elem->properties != NULL)
2670 ret->properties = xmlCopyPropList(elem->properties);
2671
2672 if (elem->nsDef != NULL)
2673 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002674 if (elem->children != NULL)
2675 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002676 return(ret);
2677}
2678 */
2679
2680/**
2681 * xmlCopyDtd:
2682 * @dtd: the dtd
2683 *
2684 * Do a copy of the dtd.
2685 *
2686 * Returns: a new xmlDtdPtr, or NULL in case of error.
2687 */
2688xmlDtdPtr
2689xmlCopyDtd(xmlDtdPtr dtd) {
2690 xmlDtdPtr ret;
2691
2692 if (dtd == NULL) return(NULL);
2693 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2694 if (ret == NULL) return(NULL);
2695 if (dtd->entities != NULL)
2696 ret->entities = (void *) xmlCopyEntitiesTable(
2697 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002698 if (dtd->notations != NULL)
2699 ret->notations = (void *) xmlCopyNotationTable(
2700 (xmlNotationTablePtr) dtd->notations);
2701 if (dtd->elements != NULL)
2702 ret->elements = (void *) xmlCopyElementTable(
2703 (xmlElementTablePtr) dtd->elements);
2704 if (dtd->attributes != NULL)
2705 ret->attributes = (void *) xmlCopyAttributeTable(
2706 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002707 return(ret);
2708}
2709
2710/**
2711 * xmlCopyDoc:
2712 * @doc: the document
2713 * @recursive: if 1 do a recursive copy.
2714 *
2715 * Do a copy of the document info. If recursive, the content tree will
2716 * be copied too as well as Dtd, namespaces and entities.
2717 *
2718 * Returns: a new xmlDocPtr, or NULL in case of error.
2719 */
2720xmlDocPtr
2721xmlCopyDoc(xmlDocPtr doc, int recursive) {
2722 xmlDocPtr ret;
2723
2724 if (doc == NULL) return(NULL);
2725 ret = xmlNewDoc(doc->version);
2726 if (ret == NULL) return(NULL);
2727 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002728 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002729 if (doc->encoding != NULL)
2730 ret->encoding = xmlStrdup(doc->encoding);
2731 ret->compression = doc->compression;
2732 ret->standalone = doc->standalone;
2733 if (!recursive) return(ret);
2734
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002735 if (doc->intSubset != NULL)
2736 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002737 if (doc->oldNs != NULL)
2738 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002739 if (doc->children != NULL) {
2740 xmlNodePtr tmp;
Daniel Veillard06047432000-04-24 11:33:38 +00002741 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2742 (xmlNodePtr)ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002743 ret->last = NULL;
2744 tmp = ret->children;
2745 while (tmp != NULL) {
2746 if (tmp->next == NULL)
2747 ret->last = tmp;
2748 tmp = tmp->next;
2749 }
2750 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002751 return(ret);
2752}
2753
2754/************************************************************************
2755 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002756 * Content access functions *
2757 * *
2758 ************************************************************************/
2759
Daniel Veillard97b58771998-10-20 06:14:16 +00002760/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002761 * xmlDocGetRootElement:
2762 * @doc: the document
2763 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002764 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002765 * containing possibly comments, PIs, etc ...).
2766 *
2767 * Returns the xmlNodePtr for the root or NULL
2768 */
2769xmlNodePtr
2770xmlDocGetRootElement(xmlDocPtr doc) {
2771 xmlNodePtr ret;
2772
2773 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002774 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002775 while (ret != NULL) {
2776 if (ret->type == XML_ELEMENT_NODE)
2777 return(ret);
2778 ret = ret->next;
2779 }
2780 return(ret);
2781}
2782
2783/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002784 * xmlDocSetRootElement:
2785 * @doc: the document
2786 * @root: the new document root element
2787 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002788 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002789 * containing possibly comments, PIs, etc ...).
2790 *
2791 * Returns the old root element if any was found
2792 */
2793xmlNodePtr
2794xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2795 xmlNodePtr old = NULL;
2796
2797 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002798 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002799 while (old != NULL) {
2800 if (old->type == XML_ELEMENT_NODE)
2801 break;
2802 old = old->next;
2803 }
2804 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002805 if (doc->children == NULL) {
2806 doc->children = root;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002807 doc->last = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002808 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002809 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002810 }
2811 } else {
2812 xmlReplaceNode(old, root);
2813 }
2814 return(old);
2815}
2816
2817/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002818 * xmlNodeSetLang:
2819 * @cur: the node being changed
2820 * @lang: the langage description
2821 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002822 * Set the language of a node, i.e. the values of the xml:lang
2823 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002824 */
2825void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002826xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002827 if (cur == NULL) return;
2828 switch(cur->type) {
2829 case XML_TEXT_NODE:
2830 case XML_CDATA_SECTION_NODE:
2831 case XML_COMMENT_NODE:
2832 case XML_DOCUMENT_NODE:
2833 case XML_DOCUMENT_TYPE_NODE:
2834 case XML_DOCUMENT_FRAG_NODE:
2835 case XML_NOTATION_NODE:
2836 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002837 case XML_DTD_NODE:
2838 case XML_ELEMENT_DECL:
2839 case XML_ATTRIBUTE_DECL:
2840 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002841 case XML_PI_NODE:
2842 case XML_ENTITY_REF_NODE:
2843 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002844 case XML_NAMESPACE_DECL:
Daniel Veillard04698d92000-09-17 16:00:22 +00002845#ifdef LIBXML_SGML_ENABLED
2846 case XML_SGML_DOCUMENT_NODE:
2847#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002848 case XML_XINCLUDE_START:
2849 case XML_XINCLUDE_END:
Daniel Veillard39c7d712000-09-10 16:14:55 +00002850 return;
2851 case XML_ELEMENT_NODE:
2852 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002853 break;
2854 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002855 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2856}
2857
2858/**
2859 * xmlNodeGetLang:
2860 * @cur: the node being checked
2861 *
2862 * Searches the language of a node, i.e. the values of the xml:lang
2863 * attribute or the one carried by the nearest ancestor.
2864 *
2865 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002866 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002867 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002868xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002869xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002870 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002871
2872 while (cur != NULL) {
2873 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2874 if (lang != NULL)
2875 return(lang);
2876 cur = cur->parent;
2877 }
2878 return(NULL);
2879}
2880
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002881
2882/**
2883 * xmlNodeSetSpacePreserve:
2884 * @cur: the node being changed
2885 * @val: the xml:space value ("0": default, 1: "preserve")
2886 *
2887 * Set (or reset) the space preserving behaviour of a node, i.e. the
2888 * value of the xml:space attribute.
2889 */
2890void
2891xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2892 if (cur == NULL) return;
2893 switch(cur->type) {
2894 case XML_TEXT_NODE:
2895 case XML_CDATA_SECTION_NODE:
2896 case XML_COMMENT_NODE:
2897 case XML_DOCUMENT_NODE:
2898 case XML_DOCUMENT_TYPE_NODE:
2899 case XML_DOCUMENT_FRAG_NODE:
2900 case XML_NOTATION_NODE:
2901 case XML_HTML_DOCUMENT_NODE:
2902 case XML_DTD_NODE:
2903 case XML_ELEMENT_DECL:
2904 case XML_ATTRIBUTE_DECL:
2905 case XML_ENTITY_DECL:
2906 case XML_PI_NODE:
2907 case XML_ENTITY_REF_NODE:
2908 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002909 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002910 case XML_XINCLUDE_START:
2911 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002912#ifdef LIBXML_SGML_ENABLED
2913 case XML_SGML_DOCUMENT_NODE:
2914#endif
2915 return;
2916 case XML_ELEMENT_NODE:
2917 case XML_ATTRIBUTE_NODE:
2918 break;
2919 }
2920 switch (val) {
2921 case 0:
2922 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2923 break;
2924 case 1:
2925 xmlSetProp(cur, BAD_CAST "xml:space",
2926 BAD_CAST "preserve");
2927 break;
2928 }
2929}
2930
Daniel Veillardb96e6431999-08-29 21:02:19 +00002931/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002932 * xmlNodeGetSpacePreserve:
2933 * @cur: the node being checked
2934 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002935 * Searches the space preserving behaviour of a node, i.e. the values
2936 * of the xml:space attribute or the one carried by the nearest
2937 * ancestor.
Daniel Veillardcf461992000-03-14 18:30:20 +00002938 *
2939 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2940 */
2941int
2942xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2943 xmlChar *space;
2944
2945 while (cur != NULL) {
2946 space = xmlGetProp(cur, BAD_CAST "xml:space");
2947 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002948 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002949 xmlFree(space);
2950 return(1);
2951 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002952 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002953 xmlFree(space);
2954 return(0);
2955 }
2956 xmlFree(space);
2957 }
2958 cur = cur->parent;
2959 }
2960 return(-1);
2961}
2962
2963/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002964 * xmlNodeSetName:
2965 * @cur: the node being changed
2966 * @name: the new tag name
2967 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002968 * Set (or reset) the name of a node.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002969 */
2970void
2971xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2972 if (cur == NULL) return;
2973 if (name == NULL) return;
2974 switch(cur->type) {
2975 case XML_TEXT_NODE:
2976 case XML_CDATA_SECTION_NODE:
2977 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002978 case XML_DOCUMENT_TYPE_NODE:
2979 case XML_DOCUMENT_FRAG_NODE:
2980 case XML_NOTATION_NODE:
2981 case XML_HTML_DOCUMENT_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002982 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002983 case XML_XINCLUDE_START:
2984 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00002985#ifdef LIBXML_SGML_ENABLED
2986 case XML_SGML_DOCUMENT_NODE:
2987#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002988 return;
2989 case XML_ELEMENT_NODE:
2990 case XML_ATTRIBUTE_NODE:
2991 case XML_PI_NODE:
2992 case XML_ENTITY_REF_NODE:
2993 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002994 case XML_DTD_NODE:
2995 case XML_DOCUMENT_NODE:
2996 case XML_ELEMENT_DECL:
2997 case XML_ATTRIBUTE_DECL:
2998 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002999 break;
3000 }
3001 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3002 cur->name = xmlStrdup(name);
3003}
3004
3005/**
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003006 * xmlNodeSetBase:
3007 * @cur: the node being changed
3008 * @uri: the new base URI
3009 *
3010 * Set (or reset) the base URI of a node, i.e. the value of the
3011 * xml:base attribute.
3012 */
3013void
3014xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3015 if (cur == NULL) return;
3016 switch(cur->type) {
3017 case XML_TEXT_NODE:
3018 case XML_CDATA_SECTION_NODE:
3019 case XML_COMMENT_NODE:
3020 case XML_DOCUMENT_NODE:
3021 case XML_DOCUMENT_TYPE_NODE:
3022 case XML_DOCUMENT_FRAG_NODE:
3023 case XML_NOTATION_NODE:
3024 case XML_HTML_DOCUMENT_NODE:
3025 case XML_DTD_NODE:
3026 case XML_ELEMENT_DECL:
3027 case XML_ATTRIBUTE_DECL:
3028 case XML_ENTITY_DECL:
3029 case XML_PI_NODE:
3030 case XML_ENTITY_REF_NODE:
3031 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003032 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003033 case XML_XINCLUDE_START:
3034 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003035#ifdef LIBXML_SGML_ENABLED
3036 case XML_SGML_DOCUMENT_NODE:
3037#endif
3038 return;
3039 case XML_ELEMENT_NODE:
3040 case XML_ATTRIBUTE_NODE:
3041 break;
3042 }
3043 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3044}
3045
3046/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003047 * xmlDocumentGetBase:
3048 * @doc: the document
3049 *
3050 * Searches for the Document BASE URL. The code should work on both XML
3051 * and HTML document.
3052 * It returns the base as defined in RFC 2396 section
3053 * 5.1.3. Base URI from the Retrieval URI
3054 * However it does not return the computed base (5.1.1 and 5.1.2), use
3055 * xmlNodeGetBase() for this
3056 *
3057 * Returns a pointer to the base URL, or NULL if not found
3058 * It's up to the caller to free the memory.
3059 */
3060xmlChar *
3061xmlDocumentGetBase(xmlDocPtr doc) {
3062 if (doc == NULL)
3063 return(NULL);
3064 if (doc->type == XML_HTML_DOCUMENT_NODE) {
3065 if (doc->URL != NULL)
3066 return(xmlStrdup(doc->URL));
3067 return(NULL);
3068 }
3069 if (doc->URL != NULL)
3070 return(xmlStrdup(doc->URL));
3071 return(NULL);
3072}
3073
3074/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00003075 * xmlNodeGetBase:
3076 * @doc: the document the node pertains to
3077 * @cur: the node being checked
3078 *
3079 * Searches for the BASE URL. The code should work on both XML
3080 * and HTML document even if base mechanisms are completely different.
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003081 * It returns the base as defined in RFC 2396 sections
3082 * 5.1.1. Base URI within Document Content
3083 * and
3084 * 5.1.2. Base URI from the Encapsulating Entity
3085 * However it does not return the document base (5.1.3), use
3086 * xmlDocumentGetBase() for this
Daniel Veillard10a2c651999-12-12 13:03:50 +00003087 *
3088 * Returns a pointer to the base URL, or NULL if not found
3089 * It's up to the caller to free the memory.
3090 */
3091xmlChar *
3092xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3093 xmlChar *base;
3094
3095 if ((cur == NULL) && (doc == NULL))
3096 return(NULL);
3097 if (doc == NULL) doc = cur->doc;
3098 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003099 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003100 while ((cur != NULL) && (cur->name != NULL)) {
3101 if (cur->type != XML_ELEMENT_NODE) {
3102 cur = cur->next;
3103 continue;
3104 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003105 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003106 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003107 continue;
3108 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003109 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003110 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003111 continue;
3112 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003113 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3114 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003115 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003116 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003117 }
3118 return(NULL);
3119 }
3120 while (cur != NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003121 if (cur->type == XML_ENTITY_DECL) {
3122 xmlEntityPtr ent = (xmlEntityPtr) cur;
3123 return(xmlStrdup(ent->URI));
3124 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003125 base = xmlGetProp(cur, BAD_CAST "xml:base");
3126 if (base != NULL)
3127 return(base);
3128 cur = cur->parent;
3129 }
3130 return(NULL);
3131}
3132
3133/**
Daniel Veillard16253641998-10-28 22:58:05 +00003134 * xmlNodeGetContent:
3135 * @cur: the node being read
3136 *
3137 * Read the value of a node, this can be either the text carried
3138 * directly by this node if it's a TEXT node or the aggregate string
3139 * of the values carried by this node child's (TEXT and ENTITY_REF).
3140 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003141 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003142 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00003143 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003144xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00003145xmlNodeGetContent(xmlNodePtr cur) {
3146 if (cur == NULL) return(NULL);
3147 switch (cur->type) {
3148 case XML_DOCUMENT_FRAG_NODE:
3149 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003150 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00003151 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003152 case XML_ATTRIBUTE_NODE: {
3153 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00003154 if (attr->parent != NULL)
3155 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003156 else
Daniel Veillardcf461992000-03-14 18:30:20 +00003157 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003158 break;
3159 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003160 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003161 case XML_PI_NODE:
3162 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003163#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00003164 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003165#else
3166 return(xmlStrdup(xmlBufferContent(cur->content)));
3167#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003168 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003169 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003170 /*
3171 * Locate the entity, and get it's content
3172 * @@@
3173 */
3174 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003175 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003176 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003177 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003178 case XML_DOCUMENT_TYPE_NODE:
3179 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003180 case XML_DTD_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003181 case XML_XINCLUDE_START:
3182 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003183#ifdef LIBXML_SGML_ENABLED
3184 case XML_SGML_DOCUMENT_NODE:
3185#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00003186 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00003187 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003188 return(xmlStrdup(((xmlNsPtr)cur)->href));
Daniel Veillardcf461992000-03-14 18:30:20 +00003189 case XML_ELEMENT_DECL:
3190 /* TODO !!! */
3191 return(NULL);
3192 case XML_ATTRIBUTE_DECL:
3193 /* TODO !!! */
3194 return(NULL);
3195 case XML_ENTITY_DECL:
3196 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00003197 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003198 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003199 case XML_TEXT_NODE:
3200 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003201#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003202 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003203#else
3204 return(xmlStrdup(xmlBufferContent(cur->content)));
3205#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003206 return(NULL);
3207 }
3208 return(NULL);
3209}
3210
3211/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003212 * xmlNodeSetContent:
3213 * @cur: the node being modified
3214 * @content: the new value of the content
3215 *
3216 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003217 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003218void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003219xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003220 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003221#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003222 xmlGenericError(xmlGenericErrorContext,
3223 "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003224#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003225 return;
3226 }
Daniel Veillard16253641998-10-28 22:58:05 +00003227 switch (cur->type) {
3228 case XML_DOCUMENT_FRAG_NODE:
3229 case XML_ELEMENT_NODE:
3230 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003231#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003232 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003233#else
3234 xmlBufferFree(cur->content);
3235#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003236 cur->content = NULL;
3237 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003238 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3239 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003240 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003241 break;
3242 case XML_ATTRIBUTE_NODE:
3243 break;
3244 case XML_TEXT_NODE:
3245 case XML_CDATA_SECTION_NODE:
3246 case XML_ENTITY_REF_NODE:
3247 case XML_ENTITY_NODE:
3248 case XML_PI_NODE:
3249 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003250 if (cur->content != NULL) {
3251#ifndef XML_USE_BUFFER_CONTENT
3252 xmlFree(cur->content);
3253#else
3254 xmlBufferFree(cur->content);
3255#endif
3256 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003257 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3258 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003259 if (content != NULL) {
3260#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003261 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003262#else
3263 cur->content = xmlBufferCreateSize(0);
3264 xmlBufferSetAllocationScheme(cur->content,
3265 xmlGetBufferAllocationScheme());
3266 xmlBufferAdd(cur->content, content, -1);
3267#endif
3268 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003269 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003271 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003272 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003273 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003274 case XML_XINCLUDE_START:
3275 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003276#ifdef LIBXML_SGML_ENABLED
3277 case XML_SGML_DOCUMENT_NODE:
3278#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003279 break;
3280 case XML_NOTATION_NODE:
3281 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003282 case XML_DTD_NODE:
3283 break;
Daniel Veillarda4964b72000-10-31 18:23:44 +00003284 case XML_NAMESPACE_DECL:
3285 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003286 case XML_ELEMENT_DECL:
3287 /* TODO !!! */
3288 break;
3289 case XML_ATTRIBUTE_DECL:
3290 /* TODO !!! */
3291 break;
3292 case XML_ENTITY_DECL:
3293 /* TODO !!! */
3294 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003295 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003296}
3297
Daniel Veillard97b58771998-10-20 06:14:16 +00003298/**
3299 * xmlNodeSetContentLen:
3300 * @cur: the node being modified
3301 * @content: the new value of the content
3302 * @len: the size of @content
3303 *
3304 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003305 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003306void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003307xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003308 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003309#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003310 xmlGenericError(xmlGenericErrorContext,
3311 "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003312#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003313 return;
3314 }
Daniel Veillard16253641998-10-28 22:58:05 +00003315 switch (cur->type) {
3316 case XML_DOCUMENT_FRAG_NODE:
3317 case XML_ELEMENT_NODE:
3318 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003319#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003320 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003321#else
3322 xmlBufferFree(cur->content);
3323#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003324 cur->content = NULL;
3325 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003326 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3327 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003328 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003329 break;
3330 case XML_ATTRIBUTE_NODE:
3331 break;
3332 case XML_TEXT_NODE:
3333 case XML_CDATA_SECTION_NODE:
3334 case XML_ENTITY_REF_NODE:
3335 case XML_ENTITY_NODE:
3336 case XML_PI_NODE:
3337 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003338 case XML_NOTATION_NODE:
3339 if (cur->content != NULL) {
3340#ifndef XML_USE_BUFFER_CONTENT
3341 xmlFree(cur->content);
3342#else
3343 xmlBufferFree(cur->content);
3344#endif
3345 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003346 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3347 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003348 if (content != NULL) {
3349#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003350 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003351#else
3352 cur->content = xmlBufferCreateSize(len);
3353 xmlBufferSetAllocationScheme(cur->content,
3354 xmlGetBufferAllocationScheme());
3355 xmlBufferAdd(cur->content, content, len);
3356#endif
3357 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003358 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003359 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003360 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003361 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003362 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003363 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003364 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003365 case XML_XINCLUDE_START:
3366 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003367#ifdef LIBXML_SGML_ENABLED
3368 case XML_SGML_DOCUMENT_NODE:
3369#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003370 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003371 case XML_ELEMENT_DECL:
3372 /* TODO !!! */
3373 break;
3374 case XML_ATTRIBUTE_DECL:
3375 /* TODO !!! */
3376 break;
3377 case XML_ENTITY_DECL:
3378 /* TODO !!! */
3379 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003380 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003381}
3382
Daniel Veillard97b58771998-10-20 06:14:16 +00003383/**
3384 * xmlNodeAddContentLen:
3385 * @cur: the node being modified
3386 * @content: extra content
3387 * @len: the size of @content
3388 *
3389 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003390 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003391void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003392xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003393 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003394#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003395 xmlGenericError(xmlGenericErrorContext,
3396 "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003397#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003398 return;
3399 }
3400 if (len <= 0) return;
3401 switch (cur->type) {
3402 case XML_DOCUMENT_FRAG_NODE:
3403 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003404 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003405
Daniel Veillardcf461992000-03-14 18:30:20 +00003406 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003407 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003408 } else {
3409 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003410#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003411 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003412#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003413 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003414 xmlBufferContent(cur->content));
3415#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003416 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003417#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003418 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003419#else
3420 xmlBufferFree(cur->content);
3421#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003422 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003423 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003424 }
3425 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003426 newNode = xmlNewTextLen(content, len);
3427 if (newNode != NULL) {
3428 xmlAddChild(cur, newNode);
3429 if ((last != NULL) && (last->next == newNode)) {
3430 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003431 }
Daniel Veillard16253641998-10-28 22:58:05 +00003432 }
3433 break;
3434 }
3435 case XML_ATTRIBUTE_NODE:
3436 break;
3437 case XML_TEXT_NODE:
3438 case XML_CDATA_SECTION_NODE:
3439 case XML_ENTITY_REF_NODE:
3440 case XML_ENTITY_NODE:
3441 case XML_PI_NODE:
3442 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003443 case XML_NOTATION_NODE:
3444 if (content != NULL) {
3445#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003446 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003447#else
3448 xmlBufferAdd(cur->content, content, len);
3449#endif
3450 }
Daniel Veillard16253641998-10-28 22:58:05 +00003451 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003452 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003453 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003454 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003455 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003456 case XML_XINCLUDE_START:
3457 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003458#ifdef LIBXML_SGML_ENABLED
3459 case XML_SGML_DOCUMENT_NODE:
3460#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003461 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003462 case XML_ELEMENT_DECL:
3463 case XML_ATTRIBUTE_DECL:
3464 case XML_ENTITY_DECL:
3465 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003466 }
3467}
3468
3469/**
3470 * xmlNodeAddContent:
3471 * @cur: the node being modified
3472 * @content: extra content
3473 *
3474 * Append the extra substring to the node content.
3475 */
3476void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003477xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003478 int len;
3479
3480 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003481#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003482 xmlGenericError(xmlGenericErrorContext,
3483 "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003484#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003485 return;
3486 }
Daniel Veillard16253641998-10-28 22:58:05 +00003487 if (content == NULL) return;
3488 len = xmlStrlen(content);
3489 xmlNodeAddContentLen(cur, content, len);
3490}
3491
3492/**
3493 * xmlTextMerge:
3494 * @first: the first text node
3495 * @second: the second text node being merged
3496 *
3497 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003498 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003499 */
3500xmlNodePtr
3501xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3502 if (first == NULL) return(second);
3503 if (second == NULL) return(first);
3504 if (first->type != XML_TEXT_NODE) return(first);
3505 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003506#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003507 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003508#else
3509 xmlNodeAddContent(first, xmlBufferContent(second->content));
3510#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003511 xmlUnlinkNode(second);
3512 xmlFreeNode(second);
3513 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003514}
3515
Daniel Veillard97b58771998-10-20 06:14:16 +00003516/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003517 * xmlGetNsList:
3518 * @doc: the document
3519 * @node: the current node
3520 *
3521 * Search all the namespace applying to a given element.
3522 * Returns an NULL terminated array of all the xmlNsPtr found
3523 * that need to be freed by the caller or NULL if no
3524 * namespace if defined
3525 */
3526xmlNsPtr *
3527xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3528 xmlNsPtr cur;
3529 xmlNsPtr *ret = NULL;
3530 int nbns = 0;
3531 int maxns = 10;
3532 int i;
3533
3534 while (node != NULL) {
3535 cur = node->nsDef;
3536 while (cur != NULL) {
3537 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003538 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003539 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003540 xmlGenericError(xmlGenericErrorContext,
3541 "xmlGetNsList : out of memory!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003542 return(NULL);
3543 }
3544 ret[nbns] = NULL;
3545 }
3546 for (i = 0;i < nbns;i++) {
3547 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003548 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003549 }
3550 if (i >= nbns) {
3551 if (nbns >= maxns) {
3552 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003553 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003554 (maxns + 1) * sizeof(xmlNsPtr));
3555 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003556 xmlGenericError(xmlGenericErrorContext,
3557 "xmlGetNsList : realloc failed!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003558 return(NULL);
3559 }
3560 }
3561 ret[nbns++] = cur;
3562 ret[nbns] = NULL;
3563 }
3564
3565 cur = cur->next;
3566 }
3567 node = node->parent;
3568 }
3569 return(ret);
3570}
3571
3572/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003573 * xmlSearchNs:
3574 * @doc: the document
3575 * @node: the current node
3576 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003577 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003578 * Search a Ns registered under a given name space for a document.
3579 * recurse on the parents until it finds the defined namespace
3580 * or return NULL otherwise.
3581 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003582 * We don't allow to cross entities boundaries. If you don't declare
3583 * the namespace within those you will be in troubles !!! A warning
3584 * is generated to cover this case.
3585 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003586 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003587 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003588xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003589xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003590 xmlNsPtr cur;
3591
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003592 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003593 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003594 if ((node->type == XML_ENTITY_REF_NODE) ||
3595 (node->type == XML_ENTITY_NODE) ||
3596 (node->type == XML_ENTITY_DECL))
3597 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003598 if (node->type == XML_ELEMENT_NODE) {
3599 cur = node->nsDef;
3600 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003601 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3602 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003603 return(cur);
3604 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003605 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003606 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003607 return(cur);
3608 cur = cur->next;
3609 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003610 }
3611 node = node->parent;
3612 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003613 return(NULL);
3614}
3615
Daniel Veillard97b58771998-10-20 06:14:16 +00003616/**
3617 * xmlSearchNsByHref:
3618 * @doc: the document
3619 * @node: the current node
3620 * @href: the namespace value
3621 *
3622 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3623 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003624 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003625 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003626xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003627xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003628 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003629 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003630
Daniel Veillard10a2c651999-12-12 13:03:50 +00003631 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003632 while (node != NULL) {
3633 cur = node->nsDef;
3634 while (cur != NULL) {
3635 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003636 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003637 /*
3638 * Check that the prefix is not shadowed between orig and node
3639 */
3640 xmlNodePtr check = orig;
3641 xmlNsPtr tst;
3642
3643 while (check != node) {
3644 tst = check->nsDef;
3645 while (tst != NULL) {
3646 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3647 goto shadowed;
3648 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003649 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003650 goto shadowed;
3651 tst = tst->next;
3652 }
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00003653 check = check->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003654 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003655 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003656 }
3657shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003658 cur = cur->next;
3659 }
3660 node = node->parent;
3661 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003662 return(NULL);
3663}
3664
3665/**
3666 * xmlNewReconciliedNs
3667 * @doc: the document
3668 * @tree: a node expected to hold the new namespace
3669 * @ns: the original namespace
3670 *
3671 * This function tries to locate a namespace definition in a tree
3672 * ancestors, or create a new namespace definition node similar to
3673 * @ns trying to reuse the same prefix. However if the given prefix is
3674 * null (default namespace) or reused within the subtree defined by
3675 * @tree or on one of its ancestors then a new prefix is generated.
3676 * Returns the (new) namespace definition or NULL in case of error
3677 */
3678xmlNsPtr
3679xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3680 xmlNsPtr def;
3681 xmlChar prefix[50];
3682 int counter = 1;
3683
3684 if (tree == NULL) {
3685#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003686 xmlGenericError(xmlGenericErrorContext,
3687 "xmlNewReconciliedNs : tree == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003688#endif
3689 return(NULL);
3690 }
3691 if (ns == NULL) {
3692#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003693 xmlGenericError(xmlGenericErrorContext,
3694 "xmlNewReconciliedNs : ns == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003695#endif
3696 return(NULL);
3697 }
3698 /*
3699 * Search an existing namespace definition inherited.
3700 */
3701 def = xmlSearchNsByHref(doc, tree, ns->href);
3702 if (def != NULL)
3703 return(def);
3704
3705 /*
3706 * Find a close prefix which is not already in use.
3707 * Let's strip namespace prefixes longer than 20 chars !
3708 */
3709 sprintf((char *) prefix, "%.20s", ns->prefix);
3710 def = xmlSearchNs(doc, tree, prefix);
3711 while (def != NULL) {
3712 if (counter > 1000) return(NULL);
3713 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3714 def = xmlSearchNs(doc, tree, prefix);
3715 }
3716
3717 /*
3718 * Ok, now we are ready to create a new one.
3719 */
3720 def = xmlNewNs(tree, ns->href, prefix);
3721 return(def);
3722}
3723
3724/**
3725 * xmlReconciliateNs
3726 * @doc: the document
3727 * @tree: a node defining the subtree to reconciliate
3728 *
3729 * This function checks that all the namespaces declared within the given
3730 * tree are properly declared. This is needed for example after Copy or Cut
3731 * and then paste operations. The subtree may still hold pointers to
3732 * namespace declarations outside the subtree or invalid/masked. As much
3733 * as possible the function try tu reuse the existing namespaces found in
3734 * the new environment. If not possible the new namespaces are redeclared
3735 * on @tree at the top of the given subtree.
3736 * Returns the number of namespace declarations created or -1 in case of error.
3737 */
3738int
3739xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3740 xmlNsPtr *oldNs = NULL;
3741 xmlNsPtr *newNs = NULL;
3742 int sizeCache = 0;
3743 int nbCache = 0;
3744
3745 xmlNsPtr n;
3746 xmlNodePtr node = tree;
3747 xmlAttrPtr attr;
3748 int ret = 0, i;
3749
3750 while (node != NULL) {
3751 /*
3752 * Reconciliate the node namespace
3753 */
3754 if (node->ns != NULL) {
3755 /*
3756 * initialize the cache if needed
3757 */
3758 if (sizeCache == 0) {
3759 sizeCache = 10;
3760 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3761 sizeof(xmlNsPtr));
3762 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003763 xmlGenericError(xmlGenericErrorContext,
3764 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003765 return(-1);
3766 }
3767 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3768 sizeof(xmlNsPtr));
3769 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003770 xmlGenericError(xmlGenericErrorContext,
3771 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003772 xmlFree(oldNs);
3773 return(-1);
3774 }
3775 }
3776 for (i = 0;i < nbCache;i++) {
3777 if (oldNs[i] == node->ns) {
3778 node->ns = newNs[i];
3779 break;
3780 }
3781 }
3782 if (i == nbCache) {
3783 /*
3784 * Ok we need to recreate a new namespace definition
3785 */
3786 n = xmlNewReconciliedNs(doc, tree, node->ns);
3787 if (n != NULL) { /* :-( what if else ??? */
3788 /*
3789 * check if we need to grow the cache buffers.
3790 */
3791 if (sizeCache <= nbCache) {
3792 sizeCache *= 2;
3793 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3794 sizeof(xmlNsPtr));
3795 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003796 xmlGenericError(xmlGenericErrorContext,
3797 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003798 xmlFree(newNs);
3799 return(-1);
3800 }
3801 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3802 sizeof(xmlNsPtr));
3803 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003804 xmlGenericError(xmlGenericErrorContext,
3805 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003806 xmlFree(oldNs);
3807 return(-1);
3808 }
3809 }
3810 newNs[nbCache] = n;
3811 oldNs[nbCache++] = node->ns;
3812 node->ns = n;
3813 }
3814 }
3815 }
3816 /*
3817 * now check for namespace hold by attributes on the node.
3818 */
3819 attr = node->properties;
3820 while (attr != NULL) {
3821 if (attr->ns != NULL) {
3822 /*
3823 * initialize the cache if needed
3824 */
3825 if (sizeCache == 0) {
3826 sizeCache = 10;
3827 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3828 sizeof(xmlNsPtr));
3829 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003830 xmlGenericError(xmlGenericErrorContext,
3831 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003832 return(-1);
3833 }
3834 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3835 sizeof(xmlNsPtr));
3836 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003837 xmlGenericError(xmlGenericErrorContext,
3838 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003839 xmlFree(oldNs);
3840 return(-1);
3841 }
3842 }
3843 for (i = 0;i < nbCache;i++) {
3844 if (oldNs[i] == attr->ns) {
3845 node->ns = newNs[i];
3846 break;
3847 }
3848 }
3849 if (i == nbCache) {
3850 /*
3851 * Ok we need to recreate a new namespace definition
3852 */
3853 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3854 if (n != NULL) { /* :-( what if else ??? */
3855 /*
3856 * check if we need to grow the cache buffers.
3857 */
3858 if (sizeCache <= nbCache) {
3859 sizeCache *= 2;
3860 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3861 sizeof(xmlNsPtr));
3862 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003863 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003864 "xmlReconciliateNs : memory pbm\n");
3865 xmlFree(newNs);
3866 return(-1);
3867 }
3868 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3869 sizeof(xmlNsPtr));
3870 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003872 "xmlReconciliateNs : memory pbm\n");
3873 xmlFree(oldNs);
3874 return(-1);
3875 }
3876 }
3877 newNs[nbCache] = n;
3878 oldNs[nbCache++] = attr->ns;
3879 attr->ns = n;
3880 }
3881 }
3882 }
3883 attr = attr->next;
3884 }
3885
3886 /*
3887 * Browse the full subtree, deep first
3888 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003889 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003890 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003891 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003892 } else if ((node != tree) && (node->next != NULL)) {
3893 /* then siblings */
3894 node = node->next;
3895 } else if (node != tree) {
3896 /* go up to parents->next if needed */
3897 while (node != tree) {
3898 if (node->parent != NULL)
3899 node = node->parent;
3900 if ((node != tree) && (node->next != NULL)) {
3901 node = node->next;
3902 break;
3903 }
3904 if (node->parent == NULL) {
3905 node = NULL;
3906 break;
3907 }
3908 }
3909 /* exit condition */
3910 if (node == tree)
3911 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003912 }
3913 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003914 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003915}
3916
Daniel Veillard97b58771998-10-20 06:14:16 +00003917/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003918 * xmlHasProp:
3919 * @node: the node
3920 * @name: the attribute name
3921 *
3922 * Search an attribute associated to a node
3923 * This function also looks in DTD attribute declaration for #FIXED or
3924 * default declaration values unless DTD use has been turned off.
3925 *
3926 * Returns the attribute or the attribute declaration or NULL if
3927 * neither was found.
3928 */
3929xmlAttrPtr
3930xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3931 xmlAttrPtr prop;
3932 xmlDocPtr doc;
3933
3934 if ((node == NULL) || (name == NULL)) return(NULL);
3935 /*
3936 * Check on the properties attached to the node
3937 */
3938 prop = node->properties;
3939 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003940 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003941 return(prop);
3942 }
3943 prop = prop->next;
3944 }
3945 if (!xmlCheckDTD) return(NULL);
3946
3947 /*
3948 * Check if there is a default declaration in the internal
3949 * or external subsets
3950 */
3951 doc = node->doc;
3952 if (doc != NULL) {
3953 xmlAttributePtr attrDecl;
3954 if (doc->intSubset != NULL) {
3955 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3956 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3957 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3958 if (attrDecl != NULL)
3959 return((xmlAttrPtr) attrDecl);
3960 }
3961 }
3962 return(NULL);
3963}
3964
3965/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003966 * xmlGetProp:
3967 * @node: the node
3968 * @name: the attribute name
3969 *
3970 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003971 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003972 * This function looks in DTD attribute declaration for #FIXED or
3973 * default declaration values unless DTD use has been turned off.
3974 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003975 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003976 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003977 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003978xmlChar *
3979xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003980 xmlAttrPtr prop;
3981 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003982
Daniel Veillard10a2c651999-12-12 13:03:50 +00003983 if ((node == NULL) || (name == NULL)) return(NULL);
3984 /*
3985 * Check on the properties attached to the node
3986 */
3987 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003988 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003989 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003990 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00003991
Daniel Veillardcf461992000-03-14 18:30:20 +00003992 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003993 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00003994 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00003995 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003996 prop = prop->next;
3997 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003998 if (!xmlCheckDTD) return(NULL);
3999
4000 /*
4001 * Check if there is a default declaration in the internal
4002 * or external subsets
4003 */
4004 doc = node->doc;
4005 if (doc != NULL) {
4006 xmlAttributePtr attrDecl;
4007 if (doc->intSubset != NULL) {
4008 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4009 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4010 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00004011 if (attrDecl != NULL)
4012 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00004013 }
4014 }
4015 return(NULL);
4016}
4017
4018/**
4019 * xmlGetNsProp:
4020 * @node: the node
4021 * @name: the attribute name
4022 * @namespace: the URI of the namespace
4023 *
4024 * Search and get the value of an attribute associated to a node
4025 * This attribute has to be anchored in the namespace specified.
4026 * This does the entity substitution.
4027 * This function looks in DTD attribute declaration for #FIXED or
4028 * default declaration values unless DTD use has been turned off.
4029 *
4030 * Returns the attribute value or NULL if not found.
4031 * It's up to the caller to free the memory.
4032 */
4033xmlChar *
4034xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00004035 xmlAttrPtr prop;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004036 xmlDocPtr doc;
4037 xmlNsPtr ns;
4038
Daniel Veillard389e6b72001-01-15 19:41:13 +00004039 if (node == NULL)
4040 return(NULL);
4041
4042 prop = node->properties;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004043 if (namespace == NULL)
4044 return(xmlGetProp(node, name));
4045 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004046 /*
4047 * One need to have
4048 * - same attribute names
4049 * - and the attribute carrying that namespace
4050 * or
4051 * no namespace on the attribute and the element carrying it
4052 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004053 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004054 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004055 (xmlStrEqual(node->ns->href, namespace))) ||
4056 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004057 xmlChar *ret;
4058
Daniel Veillardcf461992000-03-14 18:30:20 +00004059 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00004060 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4061 return(ret);
4062 }
4063 prop = prop->next;
4064 }
4065 if (!xmlCheckDTD) return(NULL);
4066
4067 /*
4068 * Check if there is a default declaration in the internal
4069 * or external subsets
4070 */
4071 doc = node->doc;
4072 if (doc != NULL) {
4073 xmlAttributePtr attrDecl;
4074 if (doc->intSubset != NULL) {
4075 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4076 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4077 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4078
Daniel Veillardc2f4df22001-01-04 14:06:39 +00004079 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004080 /*
4081 * The DTD declaration only allows a prefix search
4082 */
4083 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004084 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00004085 return(xmlStrdup(attrDecl->defaultValue));
4086 }
4087 }
4088 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004089 return(NULL);
4090}
4091
Daniel Veillard97b58771998-10-20 06:14:16 +00004092/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004093 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00004094 * @node: the node
4095 * @name: the attribute name
4096 * @value: the attribute value
4097 *
4098 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004099 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004100 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004101xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004102xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004103 xmlAttrPtr prop = node->properties;
4104
4105 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004106 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004107 if (prop->children != NULL)
4108 xmlFreeNodeList(prop->children);
4109 prop->children = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004110 prop->last = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00004111 if (value != NULL) {
4112 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00004113 xmlNodePtr tmp;
4114
Daniel Veillard51e3b151999-11-12 17:02:31 +00004115 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00004116 prop->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004117 prop->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004118 tmp = prop->children;
4119 while (tmp != NULL) {
4120 tmp->parent = (xmlNodePtr) prop;
4121 if (tmp->next == NULL)
4122 prop->last = tmp;
4123 tmp = tmp->next;
4124 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00004125 xmlFree(buffer);
4126 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004127 return(prop);
4128 }
4129 prop = prop->next;
4130 }
4131 prop = xmlNewProp(node, name, value);
4132 return(prop);
4133}
4134
Daniel Veillard97b58771998-10-20 06:14:16 +00004135/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00004136 * xmlSetNsProp:
4137 * @node: the node
4138 * @ns: the namespace definition
4139 * @name: the attribute name
4140 * @value: the attribute value
4141 *
4142 * Set (or reset) an attribute carried by a node.
4143 * The ns structure must be in scope, this is not checked.
4144 *
4145 * Returns the attribute pointer.
4146 */
4147xmlAttrPtr
4148xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4149 const xmlChar *value) {
4150 xmlAttrPtr prop;
4151
4152 if ((node == NULL) || (name == NULL))
4153 return(NULL);
4154
4155 if (ns == NULL)
4156 return(xmlSetProp(node, name, value));
4157 if (ns->href == NULL)
4158 return(NULL);
4159 prop = node->properties;
4160
4161 while (prop != NULL) {
4162 /*
4163 * One need to have
4164 * - same attribute names
4165 * - and the attribute carrying that namespace
4166 * or
4167 * no namespace on the attribute and the element carrying it
4168 */
4169 if ((xmlStrEqual(prop->name, name)) &&
4170 (((prop->ns == NULL) && (node->ns != NULL) &&
4171 (xmlStrEqual(node->ns->href, ns->href))) ||
4172 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4173 if (prop->children != NULL)
4174 xmlFreeNodeList(prop->children);
4175 prop->children = NULL;
4176 prop->last = NULL;
4177 prop->ns = ns;
4178 if (value != NULL) {
4179 xmlChar *buffer;
4180 xmlNodePtr tmp;
4181
4182 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4183 prop->children = xmlStringGetNodeList(node->doc, buffer);
4184 prop->last = NULL;
4185 tmp = prop->children;
4186 while (tmp != NULL) {
4187 tmp->parent = (xmlNodePtr) prop;
4188 if (tmp->next == NULL)
4189 prop->last = tmp;
4190 tmp = tmp->next;
4191 }
4192 xmlFree(buffer);
4193 }
4194 return(prop);
4195 }
4196 prop = prop->next;
4197 }
4198 prop = xmlNewNsProp(node, ns, name, value);
4199 return(prop);
4200}
4201
4202/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004203 * xmlNodeIsText:
4204 * @node: the node
4205 *
4206 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00004207 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00004208 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004209int
4210xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004211 if (node == NULL) return(0);
4212
Daniel Veillard0bef1311998-10-14 02:36:47 +00004213 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004214 return(0);
4215}
4216
Daniel Veillard97b58771998-10-20 06:14:16 +00004217/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004218 * xmlIsBlankNode:
4219 * @node: the node
4220 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004221 * Checks whether this node is an empty or whitespace only
4222 * (and possibly ignorable) text-node.
4223 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004224 * Returns 1 yes, 0 no
4225 */
4226int
4227xmlIsBlankNode(xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004228 const xmlChar *cur;
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004229 if (node == NULL) return(0);
4230
4231 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00004232 if (node->content == NULL) return(1);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004233#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004234 cur = node->content;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004235#else
4236 cur = xmlBufferContent(node->content);
4237#endif
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004238 while (*cur != 0) {
4239 if (!IS_BLANK(*cur)) return(0);
4240 cur++;
4241 }
4242
4243 return(1);
4244}
4245
4246/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00004247 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00004248 * @node: the node
4249 * @content: the content
4250 * @len: @content lenght
4251 *
4252 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00004253 */
Daniel Veillard97b58771998-10-20 06:14:16 +00004254
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004255void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004256xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004257 if (node == NULL) return;
4258
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004259 if ((node->type != XML_TEXT_NODE) &&
4260 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004261#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004262 xmlGenericError(xmlGenericErrorContext,
4263 "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004264#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004265 return;
4266 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004267#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00004268 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004269#else
4270 xmlBufferAdd(node->content, content, len);
4271#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004272}
4273
4274/************************************************************************
4275 * *
4276 * Output : to a FILE or in memory *
4277 * *
4278 ************************************************************************/
4279
Daniel Veillard5099ae81999-04-21 20:12:07 +00004280#define BASE_BUFFER_SIZE 4000
4281
4282/**
4283 * xmlBufferCreate:
4284 *
4285 * routine to create an XML buffer.
4286 * returns the new structure.
4287 */
4288xmlBufferPtr
4289xmlBufferCreate(void) {
4290 xmlBufferPtr ret;
4291
Daniel Veillard6454aec1999-09-02 22:04:43 +00004292 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004293 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004294 xmlGenericError(xmlGenericErrorContext,
4295 "xmlBufferCreate : out of memory!\n");
Daniel Veillard5099ae81999-04-21 20:12:07 +00004296 return(NULL);
4297 }
4298 ret->use = 0;
4299 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004300 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004301 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004302 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004303 xmlGenericError(xmlGenericErrorContext,
4304 "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00004305 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004306 return(NULL);
4307 }
4308 ret->content[0] = 0;
4309 return(ret);
4310}
4311
4312/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004313 * xmlBufferCreateSize:
4314 * @size: initial size of buffer
4315 *
4316 * routine to create an XML buffer.
4317 * returns the new structure.
4318 */
4319xmlBufferPtr
4320xmlBufferCreateSize(size_t size) {
4321 xmlBufferPtr ret;
4322
4323 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4324 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004325 xmlGenericError(xmlGenericErrorContext,
4326 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004327 return(NULL);
4328 }
4329 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004330 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004331 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00004332 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004333 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4334 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004335 xmlGenericError(xmlGenericErrorContext,
4336 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004337 xmlFree(ret);
4338 return(NULL);
4339 }
4340 ret->content[0] = 0;
4341 } else
4342 ret->content = NULL;
4343 return(ret);
4344}
4345
4346/**
Daniel Veillard06047432000-04-24 11:33:38 +00004347 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004348 * @buf: the buffer to free
4349 * @scheme: allocation scheme to use
4350 *
4351 * Sets the allocation scheme for this buffer
4352 */
4353void
4354xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4355 xmlBufferAllocationScheme scheme) {
4356 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004357#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004358 xmlGenericError(xmlGenericErrorContext,
4359 "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004360#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004361 return;
4362 }
4363
4364 buf->alloc = scheme;
4365}
4366
4367/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004368 * xmlBufferFree:
4369 * @buf: the buffer to free
4370 *
4371 * Frees an XML buffer.
4372 */
4373void
4374xmlBufferFree(xmlBufferPtr buf) {
4375 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004376#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004377 xmlGenericError(xmlGenericErrorContext,
4378 "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004379#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004380 return;
4381 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004382 if (buf->content != NULL) {
4383#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004384 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004385#else
4386 memset(buf->content, -1, buf->size);
4387#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004388 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004389 }
4390 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004391 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004392}
4393
4394/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004395 * xmlBufferEmpty:
4396 * @buf: the buffer
4397 *
4398 * empty a buffer.
4399 */
4400void
4401xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00004402 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004403 buf->use = 0;
4404 memset(buf->content, -1, buf->size);/* just for debug */
4405}
4406
4407/**
4408 * xmlBufferShrink:
4409 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004410 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004411 *
4412 * Remove the beginning of an XML buffer.
4413 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004414 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004415 */
4416int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004417xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004418 if (len == 0) return(0);
4419 if (len > buf->use) return(-1);
4420
4421 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004422 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004423
4424 buf->content[buf->use] = 0;
4425 return(len);
4426}
4427
4428/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004429 * xmlBufferGrow:
4430 * @buf: the buffer
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004431 * @len: the minimum free size to allocate
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004432 *
4433 * Grow the available space of an XML buffer.
4434 *
4435 * Returns the new available space or -1 in case of error
4436 */
4437int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004438xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004439 int size;
4440 xmlChar *newbuf;
4441
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004442 if (len + buf->use < buf->size) return(0);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004443
Daniel Veillardbe803962000-06-28 23:40:59 +00004444 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004445
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004446 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004447 if (newbuf == NULL) return(-1);
4448 buf->content = newbuf;
4449 buf->size = size;
4450 return(buf->size - buf->use);
4451}
4452
4453/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004454 * xmlBufferDump:
4455 * @file: the file output
4456 * @buf: the buffer to dump
4457 *
4458 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004459 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004460 */
4461int
4462xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4463 int ret;
4464
4465 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004466#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004467 xmlGenericError(xmlGenericErrorContext,
4468 "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004469#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004470 return(0);
4471 }
4472 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004473#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004474 xmlGenericError(xmlGenericErrorContext,
4475 "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004476#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004477 return(0);
4478 }
4479 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004480 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004481 return(ret);
4482}
4483
4484/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004485 * xmlBufferContent:
4486 * @buf: the buffer to resize
4487 *
4488 * Returns the internal content
4489 */
4490
4491const xmlChar*
4492xmlBufferContent(const xmlBufferPtr buf)
4493{
4494 if(!buf)
4495 return NULL;
4496
4497 return buf->content;
4498}
4499
4500/**
4501 * xmlBufferLength:
4502 * @buf: the buffer
4503 *
4504 * Returns the length of data in the internal content
4505 */
4506
4507int
4508xmlBufferLength(const xmlBufferPtr buf)
4509{
4510 if(!buf)
4511 return 0;
4512
4513 return buf->use;
4514}
4515
4516/**
4517 * xmlBufferResize:
4518 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004519 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004520 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004521 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004522 *
4523 * Returns 0 in case of problems, 1 otherwise
4524 */
4525int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004526xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004527{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004528 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004529 xmlChar* rebuf = NULL;
4530
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004531 /*take care of empty case*/
4532 newSize = (buf->size ? buf->size*2 : size);
4533
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004534 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004535 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004536 return 1;
4537
4538 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004539 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004540 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004541 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004542 break;
4543 case XML_BUFFER_ALLOC_EXACT:
4544 newSize = size+10;
4545 break;
4546 default:
4547 newSize = size+10;
4548 break;
4549 }
4550
4551 if (buf->content == NULL)
4552 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4553 else
4554 rebuf = (xmlChar *) xmlRealloc(buf->content,
4555 newSize * sizeof(xmlChar));
4556 if (rebuf == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004557 xmlGenericError(xmlGenericErrorContext,
4558 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004559 return 0;
4560 }
4561 buf->content = rebuf;
4562 buf->size = newSize;
4563
4564 return 1;
4565}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004566
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004567/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004568 * xmlBufferAdd:
4569 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004570 * @str: the xmlChar string
4571 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004572 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004573 * Add a string range to an XML buffer. if len == -1, the lenght of
4574 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004575 */
4576void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004577xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004578 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004579
4580 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004581#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004582 xmlGenericError(xmlGenericErrorContext,
4583 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004584#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004585 return;
4586 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004587 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004588#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004589 xmlGenericError(xmlGenericErrorContext,
4590 "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004591#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004592 return;
4593 }
4594 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004595
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004596 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004597 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004598
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004599 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004600
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004601 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004602 if (needSize > buf->size){
4603 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004604 xmlGenericError(xmlGenericErrorContext,
4605 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004606 return;
4607 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004608 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004609
4610 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004611 buf->use += len;
4612 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004613}
4614
4615/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004616 * xmlBufferAddHead:
4617 * @buf: the buffer
4618 * @str: the xmlChar string
4619 * @len: the number of xmlChar to add
4620 *
4621 * Add a string range to the beginning of an XML buffer.
4622 * if len == -1, the lenght of @str is recomputed.
4623 */
4624void
4625xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004626 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004627
4628 if (str == NULL) {
4629#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004630 xmlGenericError(xmlGenericErrorContext,
4631 "xmlBufferAdd: str == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004632#endif
4633 return;
4634 }
4635 if (len < -1) {
4636#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004637 xmlGenericError(xmlGenericErrorContext,
4638 "xmlBufferAdd: len < 0\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004639#endif
4640 return;
4641 }
4642 if (len == 0) return;
4643
4644 if (len < 0)
4645 len = xmlStrlen(str);
4646
4647 if (len <= 0) return;
4648
4649 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004650 if (needSize > buf->size){
4651 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004652 xmlGenericError(xmlGenericErrorContext,
4653 "xmlBufferAddHead : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004654 return;
4655 }
4656 }
4657
4658 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4659 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4660 buf->use += len;
4661 buf->content[buf->use] = 0;
4662}
4663
4664/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004665 * xmlBufferCat:
4666 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004667 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004668 *
4669 * Append a zero terminated string to an XML buffer.
4670 */
4671void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004672xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004673 if (str != NULL)
4674 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004675}
4676
4677/**
4678 * xmlBufferCCat:
4679 * @buf: the buffer to dump
4680 * @str: the C char string
4681 *
4682 * Append a zero terminated C string to an XML buffer.
4683 */
4684void
4685xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4686 const char *cur;
4687
4688 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004689#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004690 xmlGenericError(xmlGenericErrorContext,
4691 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004692#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004693 return;
4694 }
4695 for (cur = str;*cur != 0;cur++) {
4696 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004697 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004698 xmlGenericError(xmlGenericErrorContext,
4699 "xmlBufferCCat : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004700 return;
4701 }
4702 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004703 buf->content[buf->use++] = *cur;
4704 }
4705}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004706
Daniel Veillard97b58771998-10-20 06:14:16 +00004707/**
4708 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004709 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004710 * @string: the string to add
4711 *
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004712 * routine which manages and grows an output buffer. This one adds
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004713 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004714 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004715void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004716#ifdef VMS
4717xmlBufferWriteXmlCHAR
4718#else
4719xmlBufferWriteCHAR
4720#endif
4721(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004722 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004723}
4724
Daniel Veillard97b58771998-10-20 06:14:16 +00004725/**
4726 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004727 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004728 * @string: the string to add
4729 *
4730 * routine which manage and grows an output buffer. This one add
4731 * C chars at the end of the array.
4732 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004733void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004734xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4735 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004736}
4737
Daniel Veillard5099ae81999-04-21 20:12:07 +00004738
Daniel Veillard97b58771998-10-20 06:14:16 +00004739/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004740 * xmlBufferWriteQuotedString:
4741 * @buf: the XML buffer output
4742 * @string: the string to add
4743 *
4744 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004745 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004746 * quote or double-quotes internally
4747 */
4748void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004749xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004750 if (xmlStrchr(string, '"')) {
4751 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004752#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004753 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +00004754 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004755#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004756 }
4757 xmlBufferCCat(buf, "'");
4758 xmlBufferCat(buf, string);
4759 xmlBufferCCat(buf, "'");
4760 } else {
4761 xmlBufferCCat(buf, "\"");
4762 xmlBufferCat(buf, string);
4763 xmlBufferCCat(buf, "\"");
4764 }
4765}
4766
4767
Daniel Veillardbe803962000-06-28 23:40:59 +00004768/************************************************************************
4769 * *
4770 * Dumping XML tree content to a simple buffer *
4771 * *
4772 ************************************************************************/
4773
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004774void
Daniel Veillardcf461992000-03-14 18:30:20 +00004775xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4776 int format);
4777static void
4778xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4779 int format);
4780void
4781htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4782
Daniel Veillard011b63c1999-06-02 17:44:04 +00004783/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004784 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004785 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004786 * @cur: a namespace
4787 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004788 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004789 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004790 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004791static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004792xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004793 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004794#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004795 xmlGenericError(xmlGenericErrorContext,
4796 "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004797#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004798 return;
4799 }
4800 if (cur->type == XML_LOCAL_NAMESPACE) {
4801 /* Within the context of an element attributes */
4802 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004803 xmlBufferWriteChar(buf, " xmlns:");
4804 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004805 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004806 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004807 xmlBufferWriteChar(buf, "=");
4808 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004809 }
4810}
4811
Daniel Veillard97b58771998-10-20 06:14:16 +00004812/**
4813 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004814 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004815 * @cur: the first namespace
4816 *
4817 * Dump a list of local Namespace definitions.
4818 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004819 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004820static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004821xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004822 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004823 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004824 cur = cur->next;
4825 }
4826}
4827
Daniel Veillard97b58771998-10-20 06:14:16 +00004828/**
4829 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004830 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004831 * @doc: the document
4832 *
4833 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004834 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004835static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004836xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4837 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004838#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004839 xmlGenericError(xmlGenericErrorContext,
4840 "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004841#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004842 return;
4843 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004844 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004845 xmlBufferWriteCHAR(buf, dtd->name);
4846 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004847 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004848 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004849 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004850 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4851 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004852 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004853 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004854 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004855 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4856 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4857 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004858 return;
4859 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004860 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004861 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4862#if 0
4863 if (dtd->entities != NULL)
4864 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4865 if (dtd->notations != NULL)
4866 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4867 if (dtd->elements != NULL)
4868 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4869 if (dtd->attributes != NULL)
4870 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4871#endif
4872 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004873}
4874
Daniel Veillard97b58771998-10-20 06:14:16 +00004875/**
4876 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004877 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004878 * @doc: the document
4879 * @cur: the attribute pointer
4880 *
4881 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004882 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004883static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004884xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004885 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004886
Daniel Veillard260a68f1998-08-13 03:39:55 +00004887 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004888#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004889 xmlGenericError(xmlGenericErrorContext,
4890 "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004891#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004892 return;
4893 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004894 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004895 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4896 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4897 xmlBufferWriteChar(buf, ":");
4898 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004899 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004900 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardf060a412001-01-03 20:52:44 +00004901 if (value != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004902 xmlBufferWriteChar(buf, "=");
4903 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004904 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004905 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004906 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004907 }
4908}
4909
Daniel Veillard97b58771998-10-20 06:14:16 +00004910/**
4911 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004912 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004913 * @doc: the document
4914 * @cur: the first attribute pointer
4915 *
4916 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004917 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004918static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004919xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004920 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004921#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004922 xmlGenericError(xmlGenericErrorContext,
4923 "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004924#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004925 return;
4926 }
4927 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004928 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004929 cur = cur->next;
4930 }
4931}
4932
Daniel Veillard260a68f1998-08-13 03:39:55 +00004933
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004934
Daniel Veillard97b58771998-10-20 06:14:16 +00004935/**
4936 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004937 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004938 * @doc: the document
4939 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004940 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004941 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004942 *
4943 * Dump an XML node list, recursive behaviour,children are printed too.
4944 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004945static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004946xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4947 int format) {
4948 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004949
Daniel Veillard260a68f1998-08-13 03:39:55 +00004950 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004951#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004952 xmlGenericError(xmlGenericErrorContext,
4953 "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004954#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004955 return;
4956 }
4957 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004958 if ((format) && (xmlIndentTreeOutput) &&
4959 (cur->type == XML_ELEMENT_NODE))
4960 for (i = 0;i < level;i++)
4961 xmlBufferWriteChar(buf, " ");
4962 xmlNodeDump(buf, doc, cur, level, format);
4963 if (format) {
4964 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004965 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004966 cur = cur->next;
4967 }
4968}
4969
Daniel Veillard97b58771998-10-20 06:14:16 +00004970/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004971 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004972 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004973 * @doc: the document
4974 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004975 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004976 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004977 *
4978 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004979 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004980void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004981xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4982 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004983 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004984 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004985
4986 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004987#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004988 xmlGenericError(xmlGenericErrorContext,
4989 "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004990#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004991 return;
4992 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004993 if (cur->type == XML_XINCLUDE_START)
4994 return;
4995 if (cur->type == XML_XINCLUDE_END)
4996 return;
Daniel Veillardcf461992000-03-14 18:30:20 +00004997 if (cur->type == XML_DTD_NODE) {
4998 xmlDtdDump(buf, (xmlDtdPtr) cur);
4999 return;
5000 }
5001 if (cur->type == XML_ELEMENT_DECL) {
5002 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5003 return;
5004 }
5005 if (cur->type == XML_ATTRIBUTE_DECL) {
5006 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5007 return;
5008 }
5009 if (cur->type == XML_ENTITY_DECL) {
5010 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5011 return;
5012 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005013 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00005014 if (cur->content != NULL) {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005015 if ((cur->name == xmlStringText) ||
5016 (cur->name != xmlStringTextNoenc)) {
5017 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005018
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005019#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardf6eea272001-01-18 12:17:12 +00005020 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005021#else
Daniel Veillardf6eea272001-01-18 12:17:12 +00005022 buffer = xmlEncodeEntitiesReentrant(doc,
5023 xmlBufferContent(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005024#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00005025 if (buffer != NULL) {
5026 xmlBufferWriteCHAR(buf, buffer);
5027 xmlFree(buffer);
5028 }
5029 } else {
5030 /*
5031 * Disable escaping, needed for XSLT
5032 */
5033#ifndef XML_USE_BUFFER_CONTENT
5034 xmlBufferWriteCHAR(buf, cur->content);
5035#else
5036 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5037#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005038 }
5039 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005040 return;
5041 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005042 if (cur->type == XML_PI_NODE) {
5043 if (cur->content != NULL) {
5044 xmlBufferWriteChar(buf, "<?");
5045 xmlBufferWriteCHAR(buf, cur->name);
5046 if (cur->content != NULL) {
5047 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005048#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00005049 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005050#else
5051 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5052#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00005053 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005054 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00005055 } else {
5056 xmlBufferWriteChar(buf, "<?");
5057 xmlBufferWriteCHAR(buf, cur->name);
5058 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00005059 }
5060 return;
5061 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005062 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005063 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005064 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005065#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00005066 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005067#else
5068 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5069#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005070 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005071 }
5072 return;
5073 }
Daniel Veillardccb09631998-10-27 06:21:04 +00005074 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005075 xmlBufferWriteChar(buf, "&");
5076 xmlBufferWriteCHAR(buf, cur->name);
5077 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00005078 return;
5079 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005080 if (cur->type == XML_CDATA_SECTION_NODE) {
5081 xmlBufferWriteChar(buf, "<![CDATA[");
5082 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005083#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00005084 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005085#else
5086 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5087#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00005088 xmlBufferWriteChar(buf, "]]>");
5089 return;
5090 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005091
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005092 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00005093 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005094 while (tmp != NULL) {
5095 if ((tmp->type == XML_TEXT_NODE) ||
5096 (tmp->type == XML_ENTITY_REF_NODE)) {
5097 format = 0;
5098 break;
5099 }
5100 tmp = tmp->next;
5101 }
5102 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005103 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005104 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005105 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5106 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005107 }
5108
Daniel Veillard5099ae81999-04-21 20:12:07 +00005109 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005110 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005111 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005112 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005113 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005114
Daniel Veillardcf461992000-03-14 18:30:20 +00005115 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00005116 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005117 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005118 return;
5119 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005120 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00005121 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005122 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005123
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005124#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00005125 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005126#else
5127 buffer = xmlEncodeEntitiesReentrant(doc,
5128 xmlBufferContent(cur->content));
5129#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005130 if (buffer != NULL) {
5131 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005132 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00005133 }
5134 }
Daniel Veillardcf461992000-03-14 18:30:20 +00005135 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005136 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005137 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00005138 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005139 if ((xmlIndentTreeOutput) && (format))
5140 for (i = 0;i < level;i++)
5141 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005142 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005143 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005144 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005145 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5146 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005147 }
5148
Daniel Veillard5099ae81999-04-21 20:12:07 +00005149 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005150 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005151}
5152
Daniel Veillard97b58771998-10-20 06:14:16 +00005153/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005154 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00005155 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005156 * @doc: the document
5157 * @cur: the current node
5158 *
5159 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5160 */
5161void
5162xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5163 xmlBufferPtr buf;
5164
5165 if (cur == NULL) {
5166#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005167 xmlGenericError(xmlGenericErrorContext,
5168 "xmlElemDump : cur == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005169#endif
5170 return;
5171 }
5172 if (doc == NULL) {
5173#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005174 xmlGenericError(xmlGenericErrorContext,
5175 "xmlElemDump : doc == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005176#endif
5177 }
5178 buf = xmlBufferCreate();
5179 if (buf == NULL) return;
5180 if ((doc != NULL) &&
5181 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00005182#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005183 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00005184#else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005185 xmlGenericError(xmlGenericErrorContext,
5186 "HTML support not compiled in\n");
Daniel Veillard361d8452000-04-03 19:48:13 +00005187#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005188 } else
5189 xmlNodeDump(buf, doc, cur, 0, 1);
5190 xmlBufferDump(f, buf);
5191 xmlBufferFree(buf);
5192}
5193
Daniel Veillardbe803962000-06-28 23:40:59 +00005194/************************************************************************
5195 * *
5196 * Dumping XML tree content to an I/O output buffer *
5197 * *
5198 ************************************************************************/
5199
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005200void
Daniel Veillardbe803962000-06-28 23:40:59 +00005201xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5202 int level, int format, const char *encoding);
5203static void
5204xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5205 int level, int format, const char *encoding);
5206/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005207 * xmlNsDumpOutput:
5208 * @buf: the XML buffer output
5209 * @cur: a namespace
5210 *
5211 * Dump a local Namespace definition.
5212 * Should be called in the context of attributes dumps.
5213 */
5214static void
5215xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5216 if (cur == NULL) {
5217#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005218 xmlGenericError(xmlGenericErrorContext,
5219 "xmlNsDump : Ns == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005220#endif
5221 return;
5222 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00005223 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005224 /* Within the context of an element attributes */
5225 if (cur->prefix != NULL) {
5226 xmlOutputBufferWriteString(buf, " xmlns:");
5227 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5228 } else
5229 xmlOutputBufferWriteString(buf, " xmlns");
5230 xmlOutputBufferWriteString(buf, "=");
5231 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5232 }
5233}
5234
5235/**
5236 * xmlNsListDumpOutput:
5237 * @buf: the XML buffer output
5238 * @cur: the first namespace
5239 *
5240 * Dump a list of local Namespace definitions.
5241 * Should be called in the context of attributes dumps.
5242 */
5243static void
5244xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5245 while (cur != NULL) {
5246 xmlNsDumpOutput(buf, cur);
5247 cur = cur->next;
5248 }
5249}
5250
5251/**
5252 * xmlDtdDumpOutput:
5253 * @buf: the XML buffer output
5254 * @doc: the document
5255 * @encoding: an optional encoding string
5256 *
5257 * Dump the XML document DTD, if any.
5258 */
5259static void
5260xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5261 if (dtd == NULL) {
5262#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005263 xmlGenericError(xmlGenericErrorContext,
5264 "xmlDtdDump : no internal subset\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005265#endif
5266 return;
5267 }
5268 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5269 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5270 if (dtd->ExternalID != NULL) {
5271 xmlOutputBufferWriteString(buf, " PUBLIC ");
5272 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5273 xmlOutputBufferWriteString(buf, " ");
5274 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5275 } else if (dtd->SystemID != NULL) {
5276 xmlOutputBufferWriteString(buf, " SYSTEM ");
5277 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5278 }
5279 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5280 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5281 xmlOutputBufferWriteString(buf, ">");
5282 return;
5283 }
5284 xmlOutputBufferWriteString(buf, " [\n");
5285 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005286 xmlOutputBufferWriteString(buf, "]>");
5287}
5288
5289/**
5290 * xmlAttrDumpOutput:
5291 * @buf: the XML buffer output
5292 * @doc: the document
5293 * @cur: the attribute pointer
5294 * @encoding: an optional encoding string
5295 *
5296 * Dump an XML attribute
5297 */
5298static void
5299xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5300 const char *encoding) {
5301 xmlChar *value;
5302
5303 if (cur == NULL) {
5304#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005305 xmlGenericError(xmlGenericErrorContext,
5306 "xmlAttrDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005307#endif
5308 return;
5309 }
5310 xmlOutputBufferWriteString(buf, " ");
5311 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5312 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5313 xmlOutputBufferWriteString(buf, ":");
5314 }
5315 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5316 value = xmlNodeListGetString(doc, cur->children, 0);
5317 if (value) {
5318 xmlOutputBufferWriteString(buf, "=");
5319 xmlBufferWriteQuotedString(buf->buffer, value);
5320 xmlFree(value);
5321 } else {
5322 xmlOutputBufferWriteString(buf, "=\"\"");
5323 }
5324}
5325
5326/**
5327 * xmlAttrListDumpOutput:
5328 * @buf: the XML buffer output
5329 * @doc: the document
5330 * @cur: the first attribute pointer
5331 * @encoding: an optional encoding string
5332 *
5333 * Dump a list of XML attributes
5334 */
5335static void
5336xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5337 xmlAttrPtr cur, const char *encoding) {
5338 if (cur == NULL) {
5339#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005340 xmlGenericError(xmlGenericErrorContext,
5341 "xmlAttrListDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005342#endif
5343 return;
5344 }
5345 while (cur != NULL) {
5346 xmlAttrDumpOutput(buf, doc, cur, encoding);
5347 cur = cur->next;
5348 }
5349}
5350
5351
5352
5353/**
5354 * xmlNodeListDumpOutput:
5355 * @buf: the XML buffer output
5356 * @doc: the document
5357 * @cur: the first node
5358 * @level: the imbrication level for indenting
5359 * @format: is formatting allowed
5360 * @encoding: an optional encoding string
5361 *
5362 * Dump an XML node list, recursive behaviour,children are printed too.
5363 */
5364static void
5365xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5366 xmlNodePtr cur, int level, int format, const char *encoding) {
5367 int i;
5368
5369 if (cur == NULL) {
5370#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005371 xmlGenericError(xmlGenericErrorContext,
5372 "xmlNodeListDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005373#endif
5374 return;
5375 }
5376 while (cur != NULL) {
5377 if ((format) && (xmlIndentTreeOutput) &&
5378 (cur->type == XML_ELEMENT_NODE))
5379 for (i = 0;i < level;i++)
5380 xmlOutputBufferWriteString(buf, " ");
5381 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5382 if (format) {
5383 xmlOutputBufferWriteString(buf, "\n");
5384 }
5385 cur = cur->next;
5386 }
5387}
5388
5389/**
5390 * xmlNodeDumpOutput:
5391 * @buf: the XML buffer output
5392 * @doc: the document
5393 * @cur: the current node
5394 * @level: the imbrication level for indenting
5395 * @format: is formatting allowed
5396 * @encoding: an optional encoding string
5397 *
5398 * Dump an XML node, recursive behaviour,children are printed too.
5399 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005400void
Daniel Veillardbe803962000-06-28 23:40:59 +00005401xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5402 int level, int format, const char *encoding) {
5403 int i;
5404 xmlNodePtr tmp;
5405
5406 if (cur == NULL) {
5407#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005408 xmlGenericError(xmlGenericErrorContext,
5409 "xmlNodeDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005410#endif
5411 return;
5412 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005413 if (cur->type == XML_XINCLUDE_START)
5414 return;
5415 if (cur->type == XML_XINCLUDE_END)
5416 return;
Daniel Veillardbe803962000-06-28 23:40:59 +00005417 if (cur->type == XML_DTD_NODE) {
5418 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5419 return;
5420 }
5421 if (cur->type == XML_ELEMENT_DECL) {
5422 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5423 return;
5424 }
5425 if (cur->type == XML_ATTRIBUTE_DECL) {
5426 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5427 return;
5428 }
5429 if (cur->type == XML_ENTITY_DECL) {
5430 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5431 return;
5432 }
5433 if (cur->type == XML_TEXT_NODE) {
5434 if (cur->content != NULL) {
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005435 if ((cur->name == xmlStringText) ||
5436 (cur->name != xmlStringTextNoenc)) {
5437 xmlChar *buffer;
Daniel Veillardbe803962000-06-28 23:40:59 +00005438
5439#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005440 if (encoding == NULL)
5441 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5442 else
5443 buffer = xmlEncodeSpecialChars(doc, cur->content);
Daniel Veillardbe803962000-06-28 23:40:59 +00005444#else
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005445 if (encoding == NULL)
5446 buffer = xmlEncodeEntitiesReentrant(doc,
5447 xmlBufferContent(cur->content));
5448 else
5449 buffer = xmlEncodeSpecialChars(doc,
5450 xmlBufferContent(cur->content));
Daniel Veillardbe803962000-06-28 23:40:59 +00005451#endif
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005452 if (buffer != NULL) {
5453 xmlOutputBufferWriteString(buf, (const char *)buffer);
5454 xmlFree(buffer);
5455 }
5456 } else {
5457 /*
5458 * Disable escaping, needed for XSLT
5459 */
5460#ifndef XML_USE_BUFFER_CONTENT
5461 xmlOutputBufferWriteString(buf, cur->content);
5462#else
5463 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5464#endif
Daniel Veillardbe803962000-06-28 23:40:59 +00005465 }
5466 }
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005467
Daniel Veillardbe803962000-06-28 23:40:59 +00005468 return;
5469 }
5470 if (cur->type == XML_PI_NODE) {
5471 if (cur->content != NULL) {
5472 xmlOutputBufferWriteString(buf, "<?");
5473 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5474 if (cur->content != NULL) {
5475 xmlOutputBufferWriteString(buf, " ");
5476#ifndef XML_USE_BUFFER_CONTENT
5477 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5478#else
5479 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5480#endif
5481 }
5482 xmlOutputBufferWriteString(buf, "?>");
5483 } else {
5484 xmlOutputBufferWriteString(buf, "<?");
5485 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5486 xmlOutputBufferWriteString(buf, "?>");
5487 }
5488 return;
5489 }
5490 if (cur->type == XML_COMMENT_NODE) {
5491 if (cur->content != NULL) {
5492 xmlOutputBufferWriteString(buf, "<!--");
5493#ifndef XML_USE_BUFFER_CONTENT
5494 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5495#else
5496 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5497#endif
5498 xmlOutputBufferWriteString(buf, "-->");
5499 }
5500 return;
5501 }
5502 if (cur->type == XML_ENTITY_REF_NODE) {
5503 xmlOutputBufferWriteString(buf, "&");
5504 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5505 xmlOutputBufferWriteString(buf, ";");
5506 return;
5507 }
5508 if (cur->type == XML_CDATA_SECTION_NODE) {
5509 xmlOutputBufferWriteString(buf, "<![CDATA[");
5510 if (cur->content != NULL)
5511#ifndef XML_USE_BUFFER_CONTENT
5512 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5513#else
5514 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5515#endif
5516 xmlOutputBufferWriteString(buf, "]]>");
5517 return;
5518 }
5519
5520 if (format == 1) {
5521 tmp = cur->children;
5522 while (tmp != NULL) {
5523 if ((tmp->type == XML_TEXT_NODE) ||
5524 (tmp->type == XML_ENTITY_REF_NODE)) {
5525 format = 0;
5526 break;
5527 }
5528 tmp = tmp->next;
5529 }
5530 }
5531 xmlOutputBufferWriteString(buf, "<");
5532 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5533 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5534 xmlOutputBufferWriteString(buf, ":");
5535 }
5536
5537 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5538 if (cur->nsDef)
5539 xmlNsListDumpOutput(buf, cur->nsDef);
5540 if (cur->properties != NULL)
5541 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5542
5543 if ((cur->content == NULL) && (cur->children == NULL) &&
5544 (!xmlSaveNoEmptyTags)) {
5545 xmlOutputBufferWriteString(buf, "/>");
5546 return;
5547 }
5548 xmlOutputBufferWriteString(buf, ">");
5549 if (cur->content != NULL) {
5550 xmlChar *buffer;
5551
5552#ifndef XML_USE_BUFFER_CONTENT
5553 if (encoding == NULL)
5554 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5555 else
5556 buffer = xmlEncodeSpecialChars(doc, cur->content);
5557#else
5558 if (encoding == NULL)
5559 buffer = xmlEncodeEntitiesReentrant(doc,
5560 xmlBufferContent(cur->content));
5561 else
5562 buffer = xmlEncodeSpecialChars(doc,
5563 xmlBufferContent(cur->content));
5564#endif
5565 if (buffer != NULL) {
5566 xmlOutputBufferWriteString(buf, (const char *)buffer);
5567 xmlFree(buffer);
5568 }
5569 }
5570 if (cur->children != NULL) {
5571 if (format) xmlOutputBufferWriteString(buf, "\n");
5572 xmlNodeListDumpOutput(buf, doc, cur->children,
5573 (level >= 0?level+1:-1), format, encoding);
5574 if ((xmlIndentTreeOutput) && (format))
5575 for (i = 0;i < level;i++)
5576 xmlOutputBufferWriteString(buf, " ");
5577 }
5578 xmlOutputBufferWriteString(buf, "</");
5579 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5580 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5581 xmlOutputBufferWriteString(buf, ":");
5582 }
5583
5584 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5585 xmlOutputBufferWriteString(buf, ">");
5586}
5587
5588/**
5589 * xmlDocContentDumpOutput:
5590 * @buf: the XML buffer output
5591 * @cur: the document
5592 * @encoding: an optional encoding string
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005593 * @format: should formatting spaces been added
Daniel Veillardbe803962000-06-28 23:40:59 +00005594 *
5595 * Dump an XML document.
5596 */
5597static void
5598xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005599 const char *encoding, int format) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005600 xmlOutputBufferWriteString(buf, "<?xml version=");
5601 if (cur->version != NULL)
5602 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5603 else
5604 xmlOutputBufferWriteString(buf, "\"1.0\"");
5605 if (encoding == NULL) {
5606 if (cur->encoding != NULL)
5607 encoding = (const char *) cur->encoding;
5608 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005609 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005610 }
5611 if (encoding != NULL) {
5612 xmlOutputBufferWriteString(buf, " encoding=");
5613 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5614 }
5615 switch (cur->standalone) {
5616 case 0:
5617 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5618 break;
5619 case 1:
5620 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5621 break;
5622 }
5623 xmlOutputBufferWriteString(buf, "?>\n");
5624 if (cur->children != NULL) {
5625 xmlNodePtr child = cur->children;
5626
Daniel Veillardbe803962000-06-28 23:40:59 +00005627 while (child != NULL) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005628 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005629 xmlOutputBufferWriteString(buf, "\n");
5630 child = child->next;
5631 }
5632 }
5633}
5634
5635/************************************************************************
5636 * *
5637 * Saving functions front-ends *
5638 * *
5639 ************************************************************************/
5640
Daniel Veillard97b58771998-10-20 06:14:16 +00005641/**
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005642 * xmlDocDumpMemoryEnc:
5643 * @out_doc: Document to generate XML text from
5644 * @doc_txt_ptr: Memory pointer for allocated XML text
5645 * @doc_txt_len: Length of the generated XML text
5646 * @txt_encoding: Character encoding to use when generating XML text
5647 * @format: should formatting spaces been added
5648 *
5649 * Dump the current DOM tree into memory using the character encoding specified
5650 * by the caller. Note it is up to the caller of this function to free the
5651 * allocated memory.
5652 */
5653
5654void
5655xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5656 int * doc_txt_len, const char * txt_encoding, int format) {
5657 int dummy = 0;
5658
5659 xmlCharEncoding doc_charset;
5660 xmlOutputBufferPtr out_buff = NULL;
5661 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5662
5663 if (doc_txt_len == NULL) {
5664 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5665 }
5666
5667 if (doc_txt_ptr == NULL) {
5668 *doc_txt_len = 0;
5669 xmlGenericError(xmlGenericErrorContext,
5670 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5671 return;
5672 }
5673
5674 *doc_txt_ptr = NULL;
5675 *doc_txt_len = 0;
5676
5677 if (out_doc == NULL) {
5678 /* No document, no output */
5679 xmlGenericError(xmlGenericErrorContext,
5680 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5681 return;
5682 }
5683
5684 /*
5685 * Validate the encoding value, if provided.
5686 * This logic is copied from xmlSaveFileEnc.
5687 */
5688
5689 if (txt_encoding == NULL)
5690 txt_encoding = (const char *) out_doc->encoding;
5691 if (txt_encoding != NULL) {
5692 doc_charset = xmlParseCharEncoding(txt_encoding);
5693
5694 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5695 xmlGenericError(xmlGenericErrorContext,
5696 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5697 return;
5698
5699 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5700 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5701 if ( conv_hdlr == NULL ) {
5702 xmlGenericError(xmlGenericErrorContext,
5703 "%s: %s %s '%s'\n",
5704 "xmlDocDumpFormatMemoryEnc",
5705 "Failed to identify encoding handler for",
5706 "character set",
5707 txt_encoding);
5708 return;
5709 }
5710 }
5711 }
5712
5713 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5714 xmlGenericError(xmlGenericErrorContext,
5715 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5716 return;
5717 }
5718
5719 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
5720 xmlOutputBufferFlush(out_buff);
5721 if (out_buff->conv != NULL) {
5722 *doc_txt_len = out_buff->conv->use;
5723 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5724 } else {
5725 *doc_txt_len = out_buff->buffer->use;
5726 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5727 }
5728 (void)xmlOutputBufferClose(out_buff);
5729
5730 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5731 *doc_txt_len = 0;
5732 xmlGenericError(xmlGenericErrorContext,
5733 "xmlDocDumpFormatMemoryEnc: %s\n",
5734 "Failed to allocate memory for document text representation.");
5735 }
5736
5737 return;
5738}
5739
5740/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005741 * xmlDocDumpMemory:
5742 * @cur: the document
5743 * @mem: OUT: the memory pointer
5744 * @size: OUT: the memory lenght
5745 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005746 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005747 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005748 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005749void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005750xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005751 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5752}
Daniel Veillard5099ae81999-04-21 20:12:07 +00005753
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005754/**
5755 * xmlDocDumpFormatMemory:
5756 * @cur: the document
5757 * @mem: OUT: the memory pointer
5758 * @size: OUT: the memory lenght
5759 * @format: should formatting spaces been added
5760 *
5761 *
5762 * Dump an XML document in memory and return the xmlChar * and it's size.
5763 * It's up to the caller to free the memory.
5764 */
5765void
5766xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5767 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005768}
5769
Daniel Veillard97b58771998-10-20 06:14:16 +00005770/**
Daniel Veillard58770e72000-11-25 00:48:47 +00005771 * xmlDocDumpMemoryEnc:
5772 * @out_doc: Document to generate XML text from
5773 * @doc_txt_ptr: Memory pointer for allocated XML text
5774 * @doc_txt_len: Length of the generated XML text
5775 * @txt_encoding: Character encoding to use when generating XML text
5776 *
5777 * Dump the current DOM tree into memory using the character encoding specified
5778 * by the caller. Note it is up to the caller of this function to free the
5779 * allocated memory.
5780 */
5781
5782void
5783xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5784 int * doc_txt_len, const char * txt_encoding) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005785 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5786 txt_encoding, 1);
Daniel Veillard58770e72000-11-25 00:48:47 +00005787}
5788
5789/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005790 * xmlGetDocCompressMode:
5791 * @doc: the document
5792 *
5793 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005794 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005795 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005796int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005797xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005798 if (doc == NULL) return(-1);
5799 return(doc->compression);
5800}
5801
Daniel Veillard97b58771998-10-20 06:14:16 +00005802/**
5803 * xmlSetDocCompressMode:
5804 * @doc: the document
5805 * @mode: the compression ratio
5806 *
5807 * set the compression ratio for a document, ZLIB based
5808 * Correct values: 0 (uncompressed) to 9 (max compression)
5809 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005810void
5811xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005812 if (doc == NULL) return;
5813 if (mode < 0) doc->compression = 0;
5814 else if (mode > 9) doc->compression = 9;
5815 else doc->compression = mode;
5816}
5817
Daniel Veillard97b58771998-10-20 06:14:16 +00005818/**
5819 * xmlGetCompressMode:
5820 *
5821 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005822 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005823 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005824int
5825 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005826 return(xmlCompressMode);
5827}
Daniel Veillard97b58771998-10-20 06:14:16 +00005828
5829/**
5830 * xmlSetCompressMode:
5831 * @mode: the compression ratio
5832 *
5833 * set the default compression mode used, ZLIB based
5834 * Correct values: 0 (uncompressed) to 9 (max compression)
5835 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005836void
5837xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005838 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005839 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005840 else xmlCompressMode = mode;
5841}
5842
Daniel Veillardbe803962000-06-28 23:40:59 +00005843/**
5844 * xmlDocDump:
5845 * @f: the FILE*
5846 * @cur: the document
5847 *
5848 * Dump an XML document to an open FILE.
5849 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005850 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005851 */
5852int
5853xmlDocDump(FILE *f, xmlDocPtr cur) {
5854 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005855 const char * encoding;
5856 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005857 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005858
Daniel Veillardbe803962000-06-28 23:40:59 +00005859 if (cur == NULL) {
5860#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005861 xmlGenericError(xmlGenericErrorContext,
5862 "xmlDocDump : document == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005863#endif
5864 return(-1);
5865 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005866 encoding = (const char *) cur->encoding;
5867
5868 if (encoding != NULL) {
5869 xmlCharEncoding enc;
5870
5871 enc = xmlParseCharEncoding(encoding);
5872
5873 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005874 xmlGenericError(xmlGenericErrorContext,
5875 "xmlDocDump: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005876 return(-1);
5877 }
5878 if (enc != XML_CHAR_ENCODING_UTF8) {
5879 handler = xmlFindCharEncodingHandler(encoding);
5880 if (handler == NULL) {
5881 xmlFree((char *) cur->encoding);
5882 cur->encoding = NULL;
5883 }
5884 }
5885 }
5886 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005887 if (buf == NULL) return(-1);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005888 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005889
5890 ret = xmlOutputBufferClose(buf);
5891 return(ret);
5892}
5893
5894/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005895 * xmlSaveFileTo:
5896 * @buf: an output I/O buffer
5897 * @cur: the document
5898 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5899 *
5900 * Dump an XML document to an I/O buffer.
5901 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005902 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005903 */
5904int
5905xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5906 int ret;
5907
5908 if (buf == NULL) return(0);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005909 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005910 ret = xmlOutputBufferClose(buf);
5911 return(ret);
5912}
5913
5914/**
5915 * xmlSaveFileEnc:
5916 * @filename: the filename (or URL)
5917 * @cur: the document
5918 * @encoding: the name of an encoding (or NULL)
5919 *
5920 * Dump an XML document, converting it to the given encoding
5921 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005922 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005923 */
5924int
5925xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5926 xmlOutputBufferPtr buf;
5927 xmlCharEncodingHandlerPtr handler = NULL;
5928 int ret;
5929
5930 if (encoding != NULL) {
5931 xmlCharEncoding enc;
5932
5933 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005934 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005935 xmlGenericError(xmlGenericErrorContext,
5936 "xmlSaveFileEnc: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005937 return(-1);
5938 }
5939 if (enc != XML_CHAR_ENCODING_UTF8) {
5940 handler = xmlFindCharEncodingHandler(encoding);
5941 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005942 return(-1);
5943 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005944 }
5945 }
5946
5947 /*
5948 * save the content to a temp buffer.
5949 */
5950 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
Daniel Veillardf831bfb2001-01-16 17:26:04 +00005951 if (buf == NULL) return(-1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005952
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005953 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005954
5955 ret = xmlOutputBufferClose(buf);
5956 return(ret);
5957}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005958
5959/**
5960 * xmlSaveFile:
5961 * @filename: the filename (or URL)
5962 * @cur: the document
5963 *
5964 * Dump an XML document to a file. Will use compression if
5965 * compiled in and enabled. If @filename is "-" the stdout file is
5966 * used.
5967 * returns: the number of byte written or -1 in case of failure.
5968 */
5969int
5970xmlSaveFile(const char *filename, xmlDocPtr cur) {
5971 xmlOutputBufferPtr buf;
5972 const char *encoding;
5973 xmlCharEncodingHandlerPtr handler = NULL;
5974 int ret;
5975
5976 if (cur == NULL)
5977 return(-1);
5978 encoding = (const char *) cur->encoding;
5979
5980 /*
5981 * save the content to a temp buffer.
5982 */
5983#ifdef HAVE_ZLIB_H
5984 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00005985#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005986 if (encoding != NULL) {
5987 xmlCharEncoding enc;
5988
5989 enc = xmlParseCharEncoding(encoding);
5990
5991 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005992 xmlGenericError(xmlGenericErrorContext,
5993 "xmlSaveFile: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005994 return(-1);
5995 }
5996 if (enc != XML_CHAR_ENCODING_UTF8) {
5997 handler = xmlFindCharEncodingHandler(encoding);
5998 if (handler == NULL) {
5999 xmlFree((char *) cur->encoding);
6000 cur->encoding = NULL;
6001 }
6002 }
6003 }
6004
6005 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Daniel Veillard0cede082001-01-17 08:23:04 +00006006 if (buf == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006007
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00006008 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006009
6010 ret = xmlOutputBufferClose(buf);
6011 return(ret);
6012}
6013