Annotation of XML/tree.c, revision 1.149
1.1 veillard 1: /*
2: * tree.c : implemetation of access function for an XML tree.
1.11 veillard 3: *
4: * See Copyright for the status of this software.
5: *
1.32 daniel 6: * Daniel.Veillard@w3.org
1.145 veillard 7: *
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: *
1.1 veillard 12: */
13:
1.59 daniel 14: #ifdef WIN32
1.80 daniel 15: #include "win32config.h"
1.59 daniel 16: #else
1.60 daniel 17: #include "config.h"
1.59 daniel 18: #endif
19:
1.1 veillard 20: #include <stdio.h>
1.59 daniel 21: #include <string.h> /* for memset() only ! */
22:
23: #ifdef HAVE_CTYPE_H
1.1 veillard 24: #include <ctype.h>
1.59 daniel 25: #endif
26: #ifdef HAVE_STDLIB_H
1.23 daniel 27: #include <stdlib.h>
1.59 daniel 28: #endif
1.23 daniel 29: #ifdef HAVE_ZLIB_H
30: #include <zlib.h>
31: #endif
32:
1.101 daniel 33: #include <libxml/xmlmemory.h>
34: #include <libxml/tree.h>
35: #include <libxml/parser.h>
36: #include <libxml/entities.h>
37: #include <libxml/valid.h>
1.134 veillard 38: #include <libxml/xmlerror.h>
1.1 veillard 39:
1.61 daniel 40: static xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
1.90 daniel 41: static xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
1.12 daniel 42: int oldXMLWDcompatibility = 0;
1.99 daniel 43: int xmlIndentTreeOutput = 0;
1.70 daniel 44: xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
1.7 veillard 45:
1.23 daniel 46: static int xmlCompressMode = 0;
1.74 daniel 47: static int xmlCheckDTD = 1;
1.87 daniel 48: int xmlSaveNoEmptyTags = 0;
1.23 daniel 49:
1.99 daniel 50: #define IS_BLANK(c) \
51: (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
52:
1.140 veillard 53: #define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
1.90 daniel 54: xmlNodePtr ulccur = (n)->children; \
1.32 daniel 55: if (ulccur == NULL) { \
56: (n)->last = NULL; \
57: } else { \
1.140 veillard 58: while (ulccur->next != NULL) { \
59: ulccur->parent = (n); \
60: ulccur = ulccur->next; \
61: } \
62: ulccur->parent = (n); \
1.32 daniel 63: (n)->last = ulccur; \
1.34 daniel 64: }}
1.32 daniel 65:
1.86 daniel 66: /* #define DEBUG_BUFFER */
67: /* #define DEBUG_TREE */
68:
1.1 veillard 69: /************************************************************************
70: * *
71: * Allocation and deallocation of basic structures *
72: * *
73: ************************************************************************/
74:
1.23 daniel 75: /**
1.70 daniel 76: * xmlSetBufferAllocationScheme:
77: * @scheme: allocation method to use
78: *
79: * Set the buffer allocation method. Types are
80: * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
81: * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
82: * improves performance
83: */
84: void
85: xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
86: xmlBufferAllocScheme = scheme;
87: }
88:
89: /**
90: * xmlGetBufferAllocationScheme:
91: *
92: * Types are
93: * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
94: * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
95: * improves performance
96: *
97: * Returns the current allocation scheme
98: */
99: xmlBufferAllocationScheme
100: xmlGetBufferAllocationScheme() {
101: return xmlBufferAllocScheme;
102: }
103:
104: /**
1.23 daniel 105: * xmlNewNs:
106: * @node: the element carrying the namespace
107: * @href: the URI associated
108: * @prefix: the prefix for the namespace
109: *
1.83 daniel 110: * Creation of a new Namespace. This function will refuse to create
111: * a namespace with a similar prefix than an existing one present on this
112: * node.
1.120 veillard 113: * We use href==NULL in the case of an element creation where the namespace
114: * was not defined.
1.83 daniel 115: * Returns returns a new namespace pointer or NULL
1.1 veillard 116: */
1.28 daniel 117: xmlNsPtr
1.61 daniel 118: xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
1.16 daniel 119: xmlNsPtr cur;
1.1 veillard 120:
121: /*
1.90 daniel 122: * Allocate a new Namespace and fill the fields.
1.1 veillard 123: */
1.57 daniel 124: cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1.1 veillard 125: if (cur == NULL) {
1.134 veillard 126: xmlGenericError(xmlGenericErrorContext,
127: "xmlNewNs : malloc failed\n");
1.1 veillard 128: return(NULL);
129: }
1.90 daniel 130: memset(cur, 0, sizeof(xmlNs));
131: cur->type = XML_LOCAL_NAMESPACE;
1.1 veillard 132:
1.19 daniel 133: if (href != NULL)
134: cur->href = xmlStrdup(href);
135: if (prefix != NULL)
136: cur->prefix = xmlStrdup(prefix);
137:
138: /*
139: * Add it at the end to preserve parsing order ...
1.83 daniel 140: * and checks for existing use of the prefix
1.19 daniel 141: */
142: if (node != NULL) {
143: if (node->nsDef == NULL) {
144: node->nsDef = cur;
145: } else {
146: xmlNsPtr prev = node->nsDef;
147:
1.86 daniel 148: if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
1.128 veillard 149: (xmlStrEqual(prev->prefix, cur->prefix))) {
1.86 daniel 150: xmlFreeNs(cur);
151: return(NULL);
152: }
1.83 daniel 153: while (prev->next != NULL) {
1.86 daniel 154: prev = prev->next;
1.83 daniel 155: if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
1.128 veillard 156: (xmlStrEqual(prev->prefix, cur->prefix))) {
1.83 daniel 157: xmlFreeNs(cur);
158: return(NULL);
159: }
160: }
1.19 daniel 161: prev->next = cur;
162: }
163: }
164: return(cur);
165: }
166:
1.23 daniel 167: /**
168: * xmlSetNs:
169: * @node: a node in the document
170: * @ns: a namespace pointer
171: *
172: * Associate a namespace to a node, a posteriori.
1.19 daniel 173: */
1.28 daniel 174: void
175: xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
1.19 daniel 176: if (node == NULL) {
1.86 daniel 177: #ifdef DEBUG_TREE
1.134 veillard 178: xmlGenericError(xmlGenericErrorContext,
179: "xmlSetNs: node == NULL\n");
1.94 daniel 180: #endif
1.19 daniel 181: return;
182: }
183: node->ns = ns;
184: }
185:
1.23 daniel 186: /**
187: * xmlFreeNs:
188: * @cur: the namespace pointer
189: *
190: * Free up the structures associated to a namespace
1.1 veillard 191: */
1.28 daniel 192: void
193: xmlFreeNs(xmlNsPtr cur) {
1.1 veillard 194: if (cur == NULL) {
1.86 daniel 195: #ifdef DEBUG_TREE
1.134 veillard 196: xmlGenericError(xmlGenericErrorContext,
197: "xmlFreeNs : ns == NULL\n");
1.86 daniel 198: #endif
1.1 veillard 199: return;
200: }
1.57 daniel 201: if (cur->href != NULL) xmlFree((char *) cur->href);
202: if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
1.16 daniel 203: memset(cur, -1, sizeof(xmlNs));
1.57 daniel 204: xmlFree(cur);
1.1 veillard 205: }
206:
1.23 daniel 207: /**
208: * xmlFreeNsList:
209: * @cur: the first namespace pointer
210: *
211: * Free up all the structures associated to the chained namespaces.
1.6 veillard 212: */
1.28 daniel 213: void
214: xmlFreeNsList(xmlNsPtr cur) {
1.16 daniel 215: xmlNsPtr next;
1.6 veillard 216: if (cur == NULL) {
1.86 daniel 217: #ifdef DEBUG_TREE
1.134 veillard 218: xmlGenericError(xmlGenericErrorContext,
219: "xmlFreeNsList : ns == NULL\n");
1.86 daniel 220: #endif
1.6 veillard 221: return;
222: }
223: while (cur != NULL) {
224: next = cur->next;
1.16 daniel 225: xmlFreeNs(cur);
1.6 veillard 226: cur = next;
227: }
228: }
229:
1.23 daniel 230: /**
231: * xmlNewDtd:
232: * @doc: the document pointer
233: * @name: the DTD name
234: * @ExternalID: the external ID
235: * @SystemID: the system ID
236: *
1.94 daniel 237: * Creation of a new DTD for the external subset. To create an
238: * internal subset, use xmlCreateIntSubset().
239: *
1.36 daniel 240: * Returns a pointer to the new DTD structure
1.17 daniel 241: */
1.28 daniel 242: xmlDtdPtr
1.61 daniel 243: xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
244: const xmlChar *ExternalID, const xmlChar *SystemID) {
1.17 daniel 245: xmlDtdPtr cur;
246:
1.31 daniel 247: if ((doc != NULL) && (doc->extSubset != NULL)) {
1.86 daniel 248: #ifdef DEBUG_TREE
1.134 veillard 249: xmlGenericError(xmlGenericErrorContext,
250: "xmlNewDtd(%s): document %s already have a DTD %s\n",
1.31 daniel 251: /* !!! */ (char *) name, doc->name,
252: /* !!! */ (char *)doc->extSubset->name);
1.86 daniel 253: #endif
254: return(NULL);
1.17 daniel 255: }
256:
257: /*
258: * Allocate a new DTD and fill the fields.
259: */
1.57 daniel 260: cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
1.17 daniel 261: if (cur == NULL) {
1.134 veillard 262: xmlGenericError(xmlGenericErrorContext,
263: "xmlNewDtd : malloc failed\n");
1.31 daniel 264: return(NULL);
265: }
1.90 daniel 266: memset(cur, 0 , sizeof(xmlDtd));
267: cur->type = XML_DTD_NODE;
1.31 daniel 268:
269: if (name != NULL)
270: cur->name = xmlStrdup(name);
271: if (ExternalID != NULL)
272: cur->ExternalID = xmlStrdup(ExternalID);
273: if (SystemID != NULL)
274: cur->SystemID = xmlStrdup(SystemID);
275: if (doc != NULL)
276: doc->extSubset = cur;
1.94 daniel 277: cur->doc = doc;
1.31 daniel 278:
279: return(cur);
280: }
281:
282: /**
1.92 daniel 283: * xmlGetIntSubset:
284: * @doc: the document pointer
285: *
286: * Get the internal subset of a document
287: * Returns a pointer to the DTD structure or NULL if not found
288: */
289:
290: xmlDtdPtr
291: xmlGetIntSubset(xmlDocPtr doc) {
292: xmlNodePtr cur;
293:
294: if (doc == NULL)
295: return(NULL);
296: cur = doc->children;
297: while (cur != NULL) {
298: if (cur->type == XML_DTD_NODE)
299: return((xmlDtdPtr) cur);
300: cur = cur->next;
301: }
302: return((xmlDtdPtr) doc->intSubset);
303: }
304:
305: /**
1.31 daniel 306: * xmlCreateIntSubset:
307: * @doc: the document pointer
308: * @name: the DTD name
309: * @ExternalID: the external ID
310: * @SystemID: the system ID
311: *
1.36 daniel 312: * Create the internal subset of a document
313: * Returns a pointer to the new DTD structure
1.31 daniel 314: */
315: xmlDtdPtr
1.61 daniel 316: xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
317: const xmlChar *ExternalID, const xmlChar *SystemID) {
1.31 daniel 318: xmlDtdPtr cur;
319:
1.92 daniel 320: if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
1.86 daniel 321: #ifdef DEBUG_TREE
1.134 veillard 322: xmlGenericError(xmlGenericErrorContext,
323:
1.31 daniel 324: "xmlCreateIntSubset(): document %s already have an internal subset\n",
325: doc->name);
1.86 daniel 326: #endif
1.31 daniel 327: return(NULL);
328: }
329:
330: /*
331: * Allocate a new DTD and fill the fields.
332: */
1.57 daniel 333: cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
1.31 daniel 334: if (cur == NULL) {
1.134 veillard 335: xmlGenericError(xmlGenericErrorContext,
336: "xmlNewDtd : malloc failed\n");
1.17 daniel 337: return(NULL);
338: }
1.90 daniel 339: memset(cur, 0, sizeof(xmlDtd));
340: cur->type = XML_DTD_NODE;
1.17 daniel 341:
342: if (name != NULL)
343: cur->name = xmlStrdup(name);
344: if (ExternalID != NULL)
345: cur->ExternalID = xmlStrdup(ExternalID);
346: if (SystemID != NULL)
347: cur->SystemID = xmlStrdup(SystemID);
1.90 daniel 348: if (doc != NULL) {
1.31 daniel 349: doc->intSubset = cur;
1.90 daniel 350: cur->parent = doc;
1.94 daniel 351: cur->doc = doc;
1.92 daniel 352: if (doc->children == NULL) {
353: doc->children = (xmlNodePtr) cur;
354: doc->last = (xmlNodePtr) cur;
355: } else {
356: xmlNodePtr prev;
357:
1.119 veillard 358: if (doc->type == XML_HTML_DOCUMENT_NODE) {
359: prev = doc->children;
360: prev->prev = (xmlNodePtr) cur;
361: cur->next = prev;
362: doc->children = (xmlNodePtr) cur;
363: } else {
364: prev = doc->last;
365: prev->next = (xmlNodePtr) cur;
366: cur->prev = prev;
367: doc->last = (xmlNodePtr) cur;
368: }
1.92 daniel 369: }
1.90 daniel 370: }
1.17 daniel 371: return(cur);
372: }
373:
1.23 daniel 374: /**
375: * xmlFreeDtd:
376: * @cur: the DTD structure to free up
377: *
378: * Free a DTD structure.
1.17 daniel 379: */
1.28 daniel 380: void
381: xmlFreeDtd(xmlDtdPtr cur) {
1.17 daniel 382: if (cur == NULL) {
1.86 daniel 383: #ifdef DEBUG_TREE
1.134 veillard 384: xmlGenericError(xmlGenericErrorContext,
385: "xmlFreeDtd : DTD == NULL\n");
1.86 daniel 386: #endif
1.17 daniel 387: return;
388: }
1.97 daniel 389: if (cur->children != NULL) {
390: xmlNodePtr next, c = cur->children;
391:
392: /*
393: * Cleanup all the DTD comments they are not in the Dtd
394: * indexes.
395: */
396: while (c != NULL) {
397: next = c->next;
398: if (c->type == XML_COMMENT_NODE) {
399: xmlUnlinkNode(c);
400: xmlFreeNode(c);
401: }
402: c = next;
403: }
404: }
1.57 daniel 405: if (cur->name != NULL) xmlFree((char *) cur->name);
406: if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
407: if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
1.97 daniel 408: /* TODO !!! */
1.35 daniel 409: if (cur->notations != NULL)
410: xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1.97 daniel 411:
1.17 daniel 412: if (cur->elements != NULL)
1.33 daniel 413: xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1.34 daniel 414: if (cur->attributes != NULL)
415: xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1.17 daniel 416: if (cur->entities != NULL)
417: xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1.132 veillard 418: if (cur->pentities != NULL)
419: xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1.97 daniel 420:
1.17 daniel 421: memset(cur, -1, sizeof(xmlDtd));
1.57 daniel 422: xmlFree(cur);
1.17 daniel 423: }
424:
1.23 daniel 425: /**
426: * xmlNewDoc:
1.61 daniel 427: * @version: xmlChar string giving the version of XML "1.0"
1.23 daniel 428: *
1.36 daniel 429: * Returns a new document
1.1 veillard 430: */
1.28 daniel 431: xmlDocPtr
1.61 daniel 432: xmlNewDoc(const xmlChar *version) {
1.1 veillard 433: xmlDocPtr cur;
434:
1.130 veillard 435: if (version == NULL)
436: version = (const xmlChar *) "1.0";
1.1 veillard 437:
438: /*
439: * Allocate a new document and fill the fields.
440: */
1.57 daniel 441: cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1.1 veillard 442: if (cur == NULL) {
1.134 veillard 443: xmlGenericError(xmlGenericErrorContext,
444: "xmlNewDoc : malloc failed\n");
1.1 veillard 445: return(NULL);
446: }
1.90 daniel 447: memset(cur, 0, sizeof(xmlDoc));
448: cur->type = XML_DOCUMENT_NODE;
1.1 veillard 449:
1.7 veillard 450: cur->version = xmlStrdup(version);
1.15 daniel 451: cur->standalone = -1;
1.68 daniel 452: cur->compression = -1; /* not initialized */
1.94 daniel 453: cur->doc = cur;
1.1 veillard 454: return(cur);
455: }
456:
1.23 daniel 457: /**
458: * xmlFreeDoc:
459: * @cur: pointer to the document
460: * @:
461: *
462: * Free up all the structures used by a document, tree included.
1.1 veillard 463: */
1.28 daniel 464: void
465: xmlFreeDoc(xmlDocPtr cur) {
1.1 veillard 466: if (cur == NULL) {
1.31 daniel 467: #ifdef DEBUG_TREE
1.134 veillard 468: xmlGenericError(xmlGenericErrorContext,
469: "xmlFreeDoc : document == NULL\n");
1.31 daniel 470: #endif
1.1 veillard 471: return;
472: }
1.57 daniel 473: if (cur->version != NULL) xmlFree((char *) cur->version);
474: if (cur->name != NULL) xmlFree((char *) cur->name);
475: if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
1.90 daniel 476: if (cur->children != NULL) xmlFreeNodeList(cur->children);
1.31 daniel 477: if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
478: if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
479: if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1.52 daniel 480: if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1.58 daniel 481: if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1.100 daniel 482: if (cur->URL != NULL) xmlFree((char *) cur->URL);
1.1 veillard 483: memset(cur, -1, sizeof(xmlDoc));
1.57 daniel 484: xmlFree(cur);
1.1 veillard 485: }
486:
1.23 daniel 487: /**
1.28 daniel 488: * xmlStringLenGetNodeList:
489: * @doc: the document
490: * @value: the value of the text
1.36 daniel 491: * @len: the length of the string value
1.28 daniel 492: *
493: * Parse the value string and build the node list associated. Should
494: * produce a flat tree with only TEXTs and ENTITY_REFs.
1.36 daniel 495: * Returns a pointer to the first child
1.28 daniel 496: */
497: xmlNodePtr
1.61 daniel 498: xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1.28 daniel 499: xmlNodePtr ret = NULL, last = NULL;
500: xmlNodePtr node;
1.61 daniel 501: xmlChar *val;
502: const xmlChar *cur = value;
503: const xmlChar *q;
1.28 daniel 504: xmlEntityPtr ent;
505:
506: if (value == NULL) return(NULL);
507:
508: q = cur;
509: while ((*cur != 0) && (cur - value < len)) {
510: if (*cur == '&') {
511: /*
512: * Save the current text.
513: */
514: if (cur != q) {
515: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
516: xmlNodeAddContentLen(last, q, cur - q);
517: } else {
518: node = xmlNewDocTextLen(doc, q, cur - q);
519: if (node == NULL) return(ret);
520: if (last == NULL)
521: last = ret = node;
522: else {
523: last->next = node;
524: node->prev = last;
525: last = node;
526: }
527: }
528: }
529: /*
530: * Read the entity string
531: */
532: cur++;
533: q = cur;
534: while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
535: if ((*cur == 0) || (cur - value >= len)) {
1.86 daniel 536: #ifdef DEBUG_TREE
1.134 veillard 537: xmlGenericError(xmlGenericErrorContext,
1.44 daniel 538: "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1.86 daniel 539: #endif
1.28 daniel 540: return(ret);
541: }
542: if (cur != q) {
543: /*
544: * Predefined entities don't generate nodes
545: */
546: val = xmlStrndup(q, cur - q);
547: ent = xmlGetDocEntity(doc, val);
548: if ((ent != NULL) &&
1.95 daniel 549: (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1.28 daniel 550: if (last == NULL) {
551: node = xmlNewDocText(doc, ent->content);
552: last = ret = node;
553: } else
554: xmlNodeAddContent(last, ent->content);
555:
556: } else {
557: /*
558: * Create a new REFERENCE_REF node
559: */
560: node = xmlNewReference(doc, val);
1.30 daniel 561: if (node == NULL) {
1.57 daniel 562: if (val != NULL) xmlFree(val);
1.30 daniel 563: return(ret);
564: }
1.28 daniel 565: if (last == NULL)
566: last = ret = node;
567: else {
568: last->next = node;
569: node->prev = last;
570: last = node;
571: }
572: }
1.57 daniel 573: xmlFree(val);
1.28 daniel 574: }
575: cur++;
576: q = cur;
577: } else
578: cur++;
579: }
580: if (cur != q) {
581: /*
582: * Handle the last piece of text.
583: */
584: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
585: xmlNodeAddContentLen(last, q, cur - q);
586: } else {
587: node = xmlNewDocTextLen(doc, q, cur - q);
588: if (node == NULL) return(ret);
589: if (last == NULL)
590: last = ret = node;
591: else {
592: last->next = node;
593: node->prev = last;
594: last = node;
595: }
596: }
597: }
598: return(ret);
599: }
600:
601: /**
1.24 daniel 602: * xmlStringGetNodeList:
603: * @doc: the document
1.23 daniel 604: * @value: the value of the attribute
605: *
1.24 daniel 606: * Parse the value string and build the node list associated. Should
607: * produce a flat tree with only TEXTs and ENTITY_REFs.
1.36 daniel 608: * Returns a pointer to the first child
1.23 daniel 609: */
1.28 daniel 610: xmlNodePtr
1.61 daniel 611: xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1.23 daniel 612: xmlNodePtr ret = NULL, last = NULL;
613: xmlNodePtr node;
1.61 daniel 614: xmlChar *val;
615: const xmlChar *cur = value;
616: const xmlChar *q;
1.28 daniel 617: xmlEntityPtr ent;
1.23 daniel 618:
619: if (value == NULL) return(NULL);
620:
621: q = cur;
622: while (*cur != 0) {
623: if (*cur == '&') {
1.28 daniel 624: /*
625: * Save the current text.
626: */
1.23 daniel 627: if (cur != q) {
1.28 daniel 628: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
629: xmlNodeAddContentLen(last, q, cur - q);
630: } else {
631: node = xmlNewDocTextLen(doc, q, cur - q);
632: if (node == NULL) return(ret);
633: if (last == NULL)
634: last = ret = node;
635: else {
636: last->next = node;
637: node->prev = last;
638: last = node;
639: }
1.23 daniel 640: }
641: }
1.28 daniel 642: /*
643: * Read the entity string
644: */
1.23 daniel 645: cur++;
646: q = cur;
647: while ((*cur != 0) && (*cur != ';')) cur++;
648: if (*cur == 0) {
1.86 daniel 649: #ifdef DEBUG_TREE
1.134 veillard 650: xmlGenericError(xmlGenericErrorContext,
1.24 daniel 651: "xmlStringGetNodeList: unterminated entity %30s\n", q);
1.86 daniel 652: #endif
1.23 daniel 653: return(ret);
654: }
655: if (cur != q) {
1.28 daniel 656: /*
657: * Predefined entities don't generate nodes
658: */
1.23 daniel 659: val = xmlStrndup(q, cur - q);
1.28 daniel 660: ent = xmlGetDocEntity(doc, val);
661: if ((ent != NULL) &&
1.95 daniel 662: (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1.28 daniel 663: if (last == NULL) {
664: node = xmlNewDocText(doc, ent->content);
665: last = ret = node;
666: } else
667: xmlNodeAddContent(last, ent->content);
668:
669: } else {
670: /*
671: * Create a new REFERENCE_REF node
672: */
673: node = xmlNewReference(doc, val);
1.30 daniel 674: if (node == NULL) {
1.57 daniel 675: if (val != NULL) xmlFree(val);
1.30 daniel 676: return(ret);
677: }
1.28 daniel 678: if (last == NULL)
679: last = ret = node;
680: else {
681: last->next = node;
682: node->prev = last;
683: last = node;
684: }
1.23 daniel 685: }
1.57 daniel 686: xmlFree(val);
1.23 daniel 687: }
688: cur++;
689: q = cur;
690: } else
691: cur++;
692: }
693: if (cur != q) {
1.28 daniel 694: /*
695: * Handle the last piece of text.
696: */
697: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
698: xmlNodeAddContentLen(last, q, cur - q);
699: } else {
700: node = xmlNewDocTextLen(doc, q, cur - q);
701: if (node == NULL) return(ret);
702: if (last == NULL)
703: last = ret = node;
704: else {
705: last->next = node;
706: node->prev = last;
707: last = node;
708: }
1.23 daniel 709: }
710: }
711: return(ret);
712: }
713:
714: /**
1.24 daniel 715: * xmlNodeListGetString:
1.23 daniel 716: * @doc: the document
1.24 daniel 717: * @list: a Node list
1.23 daniel 718: * @inLine: should we replace entity contents or show their external form
719: *
1.24 daniel 720: * Returns the string equivalent to the text contained in the Node list
721: * made of TEXTs and ENTITY_REFs
1.36 daniel 722: * Returns a pointer to the string copy, the calller must free it.
1.23 daniel 723: */
1.61 daniel 724: xmlChar *
1.28 daniel 725: xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
1.24 daniel 726: xmlNodePtr node = list;
1.61 daniel 727: xmlChar *ret = NULL;
1.23 daniel 728: xmlEntityPtr ent;
729:
1.24 daniel 730: if (list == NULL) return(NULL);
1.23 daniel 731:
732: while (node != NULL) {
1.118 veillard 733: if ((node->type == XML_TEXT_NODE) ||
734: (node->type == XML_CDATA_SECTION_NODE)) {
1.84 daniel 735: if (inLine) {
1.70 daniel 736: #ifndef XML_USE_BUFFER_CONTENT
1.23 daniel 737: ret = xmlStrcat(ret, node->content);
1.70 daniel 738: #else
739: ret = xmlStrcat(ret, xmlBufferContent(node->content));
740: #endif
741: } else {
1.61 daniel 742: xmlChar *buffer;
1.45 daniel 743:
1.70 daniel 744: #ifndef XML_USE_BUFFER_CONTENT
1.46 daniel 745: buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1.70 daniel 746: #else
747: buffer = xmlEncodeEntitiesReentrant(doc,
748: xmlBufferContent(node->content));
749: #endif
1.45 daniel 750: if (buffer != NULL) {
751: ret = xmlStrcat(ret, buffer);
1.57 daniel 752: xmlFree(buffer);
1.45 daniel 753: }
754: }
1.23 daniel 755: } else if (node->type == XML_ENTITY_REF_NODE) {
756: if (inLine) {
757: ent = xmlGetDocEntity(doc, node->name);
758: if (ent != NULL)
759: ret = xmlStrcat(ret, ent->content);
1.70 daniel 760: else {
761: #ifndef XML_USE_BUFFER_CONTENT
1.23 daniel 762: ret = xmlStrcat(ret, node->content);
1.70 daniel 763: #else
764: ret = xmlStrcat(ret, xmlBufferContent(node->content));
765: #endif
766: }
1.23 daniel 767: } else {
1.61 daniel 768: xmlChar buf[2];
1.23 daniel 769: buf[0] = '&'; buf[1] = 0;
770: ret = xmlStrncat(ret, buf, 1);
771: ret = xmlStrcat(ret, node->name);
772: buf[0] = ';'; buf[1] = 0;
773: ret = xmlStrncat(ret, buf, 1);
774: }
1.24 daniel 775: }
776: #if 0
777: else {
1.134 veillard 778: xmlGenericError(xmlGenericErrorContext,
779: "xmlGetNodeListString : invalide node type %d\n",
1.23 daniel 780: node->type);
781: }
1.24 daniel 782: #endif
1.23 daniel 783: node = node->next;
784: }
785: return(ret);
786: }
787:
788: /**
1.108 daniel 789: * xmlNodeListGetRawString:
790: * @doc: the document
791: * @list: a Node list
792: * @inLine: should we replace entity contents or show their external form
793: *
794: * Returns the string equivalent to the text contained in the Node list
795: * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
796: * this function doesn't do any character encoding handling.
797: *
798: * Returns a pointer to the string copy, the calller must free it.
799: */
800: xmlChar *
801: xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
802: xmlNodePtr node = list;
803: xmlChar *ret = NULL;
804: xmlEntityPtr ent;
805:
806: if (list == NULL) return(NULL);
807:
808: while (node != NULL) {
809: if (node->type == XML_TEXT_NODE) {
810: if (inLine) {
811: #ifndef XML_USE_BUFFER_CONTENT
812: ret = xmlStrcat(ret, node->content);
813: #else
814: ret = xmlStrcat(ret, xmlBufferContent(node->content));
815: #endif
816: } else {
817: xmlChar *buffer;
818:
819: #ifndef XML_USE_BUFFER_CONTENT
820: buffer = xmlEncodeSpecialChars(doc, node->content);
821: #else
822: buffer = xmlEncodeSpecialChars(doc,
823: xmlBufferContent(node->content));
824: #endif
825: if (buffer != NULL) {
826: ret = xmlStrcat(ret, buffer);
827: xmlFree(buffer);
828: }
829: }
830: } else if (node->type == XML_ENTITY_REF_NODE) {
831: if (inLine) {
832: ent = xmlGetDocEntity(doc, node->name);
833: if (ent != NULL)
834: ret = xmlStrcat(ret, ent->content);
835: else {
836: #ifndef XML_USE_BUFFER_CONTENT
837: ret = xmlStrcat(ret, node->content);
838: #else
839: ret = xmlStrcat(ret, xmlBufferContent(node->content));
840: #endif
841: }
842: } else {
843: xmlChar buf[2];
844: buf[0] = '&'; buf[1] = 0;
845: ret = xmlStrncat(ret, buf, 1);
846: ret = xmlStrcat(ret, node->name);
847: buf[0] = ';'; buf[1] = 0;
848: ret = xmlStrncat(ret, buf, 1);
849: }
850: }
851: #if 0
852: else {
1.134 veillard 853: xmlGenericError(xmlGenericErrorContext,
854: "xmlGetNodeListString : invalide node type %d\n",
1.108 daniel 855: node->type);
856: }
857: #endif
858: node = node->next;
859: }
860: return(ret);
861: }
862:
863: /**
1.23 daniel 864: * xmlNewProp:
865: * @node: the holding node
866: * @name: the name of the attribute
867: * @value: the value of the attribute
868: *
869: * Create a new property carried by a node.
1.36 daniel 870: * Returns a pointer to the attribute
1.1 veillard 871: */
1.28 daniel 872: xmlAttrPtr
1.61 daniel 873: xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1.20 daniel 874: xmlAttrPtr cur;
1.1 veillard 875:
876: if (name == NULL) {
1.86 daniel 877: #ifdef DEBUG_TREE
1.134 veillard 878: xmlGenericError(xmlGenericErrorContext,
879: "xmlNewProp : name == NULL\n");
1.86 daniel 880: #endif
1.1 veillard 881: return(NULL);
882: }
883:
884: /*
885: * Allocate a new property and fill the fields.
886: */
1.57 daniel 887: cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1.1 veillard 888: if (cur == NULL) {
1.134 veillard 889: xmlGenericError(xmlGenericErrorContext,
890: "xmlNewProp : malloc failed\n");
1.1 veillard 891: return(NULL);
892: }
1.90 daniel 893: memset(cur, 0, sizeof(xmlAttr));
894: cur->type = XML_ATTRIBUTE_NODE;
1.1 veillard 895:
1.90 daniel 896: cur->parent = node;
1.56 daniel 897: cur->name = xmlStrdup(name);
1.67 daniel 898: if (value != NULL) {
899: xmlChar *buffer;
1.94 daniel 900: xmlNodePtr tmp;
901:
1.67 daniel 902: buffer = xmlEncodeEntitiesReentrant(node->doc, value);
1.90 daniel 903: cur->children = xmlStringGetNodeList(node->doc, buffer);
1.140 veillard 904: cur->last = NULL;
1.94 daniel 905: tmp = cur->children;
906: while (tmp != NULL) {
907: tmp->parent = (xmlNodePtr) cur;
908: if (tmp->next == NULL)
909: cur->last = tmp;
910: tmp = tmp->next;
911: }
1.67 daniel 912: xmlFree(buffer);
913: }
1.56 daniel 914:
915: /*
916: * Add it at the end to preserve parsing order ...
917: */
918: if (node != NULL) {
919: if (node->properties == NULL) {
920: node->properties = cur;
921: } else {
922: xmlAttrPtr prev = node->properties;
923:
924: while (prev->next != NULL) prev = prev->next;
925: prev->next = cur;
1.94 daniel 926: cur->prev = prev;
1.56 daniel 927: }
928: }
929: return(cur);
930: }
931:
932: /**
933: * xmlNewNsProp:
934: * @node: the holding node
935: * @ns: the namespace
936: * @name: the name of the attribute
937: * @value: the value of the attribute
938: *
939: * Create a new property tagged with a namespace and carried by a node.
940: * Returns a pointer to the attribute
941: */
942: xmlAttrPtr
1.61 daniel 943: xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
944: const xmlChar *value) {
1.56 daniel 945: xmlAttrPtr cur;
946:
947: if (name == NULL) {
1.86 daniel 948: #ifdef DEBUG_TREE
1.134 veillard 949: xmlGenericError(xmlGenericErrorContext,
950: "xmlNewProp : name == NULL\n");
1.86 daniel 951: #endif
1.56 daniel 952: return(NULL);
953: }
954:
955: /*
956: * Allocate a new property and fill the fields.
957: */
1.57 daniel 958: cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1.56 daniel 959: if (cur == NULL) {
1.134 veillard 960: xmlGenericError(xmlGenericErrorContext,
961: "xmlNewProp : malloc failed\n");
1.56 daniel 962: return(NULL);
963: }
1.90 daniel 964: memset(cur, 0, sizeof(xmlAttr));
965: cur->type = XML_ATTRIBUTE_NODE;
1.56 daniel 966:
1.90 daniel 967: cur->parent = node;
1.94 daniel 968: if (node != NULL)
969: cur->doc = node->doc;
1.56 daniel 970: cur->ns = ns;
1.7 veillard 971: cur->name = xmlStrdup(name);
1.94 daniel 972: if (value != NULL) {
973: xmlChar *buffer;
974: xmlNodePtr tmp;
975:
976: buffer = xmlEncodeEntitiesReentrant(node->doc, value);
977: cur->children = xmlStringGetNodeList(node->doc, buffer);
1.140 veillard 978: cur->last = NULL;
1.94 daniel 979: tmp = cur->children;
980: while (tmp != NULL) {
981: tmp->parent = (xmlNodePtr) cur;
982: if (tmp->next == NULL)
983: cur->last = tmp;
984: tmp = tmp->next;
985: }
986: xmlFree(buffer);
987: }
1.17 daniel 988:
989: /*
990: * Add it at the end to preserve parsing order ...
991: */
1.1 veillard 992: if (node != NULL) {
1.17 daniel 993: if (node->properties == NULL) {
994: node->properties = cur;
995: } else {
1.20 daniel 996: xmlAttrPtr prev = node->properties;
1.17 daniel 997:
998: while (prev->next != NULL) prev = prev->next;
999: prev->next = cur;
1.94 daniel 1000: cur->prev = prev;
1.17 daniel 1001: }
1002: }
1.1 veillard 1003: return(cur);
1004: }
1005:
1.23 daniel 1006: /**
1007: * xmlNewDocProp:
1008: * @doc: the document
1009: * @name: the name of the attribute
1010: * @value: the value of the attribute
1011: *
1012: * Create a new property carried by a document.
1.36 daniel 1013: * Returns a pointer to the attribute
1.23 daniel 1014: */
1.28 daniel 1015: xmlAttrPtr
1.61 daniel 1016: xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1.23 daniel 1017: xmlAttrPtr cur;
1018:
1019: if (name == NULL) {
1.86 daniel 1020: #ifdef DEBUG_TREE
1.134 veillard 1021: xmlGenericError(xmlGenericErrorContext,
1022: "xmlNewProp : name == NULL\n");
1.86 daniel 1023: #endif
1.23 daniel 1024: return(NULL);
1025: }
1026:
1027: /*
1028: * Allocate a new property and fill the fields.
1029: */
1.57 daniel 1030: cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1.23 daniel 1031: if (cur == NULL) {
1.134 veillard 1032: xmlGenericError(xmlGenericErrorContext,
1033: "xmlNewProp : malloc failed\n");
1.23 daniel 1034: return(NULL);
1035: }
1.90 daniel 1036: memset(cur, 0, sizeof(xmlAttr));
1037: cur->type = XML_ATTRIBUTE_NODE;
1.23 daniel 1038:
1039: cur->name = xmlStrdup(name);
1.94 daniel 1040: cur->doc = doc;
1.140 veillard 1041: if (value != NULL) {
1042: xmlNodePtr tmp;
1043:
1.90 daniel 1044: cur->children = xmlStringGetNodeList(doc, value);
1.140 veillard 1045: cur->last = NULL;
1046:
1047: tmp = cur->children;
1048: while (tmp != NULL) {
1049: tmp->parent = (xmlNodePtr) cur;
1050: if (tmp->next == NULL)
1051: cur->last = tmp;
1052: tmp = tmp->next;
1053: }
1054: }
1.23 daniel 1055: return(cur);
1056: }
1057:
1058: /**
1059: * xmlFreePropList:
1060: * @cur: the first property in the list
1061: *
1.90 daniel 1062: * Free a property and all its siblings, all the children are freed too.
1.1 veillard 1063: */
1.28 daniel 1064: void
1065: xmlFreePropList(xmlAttrPtr cur) {
1.20 daniel 1066: xmlAttrPtr next;
1.1 veillard 1067: if (cur == NULL) {
1.86 daniel 1068: #ifdef DEBUG_TREE
1.134 veillard 1069: xmlGenericError(xmlGenericErrorContext,
1070: "xmlFreePropList : property == NULL\n");
1.86 daniel 1071: #endif
1.1 veillard 1072: return;
1073: }
1074: while (cur != NULL) {
1075: next = cur->next;
1076: xmlFreeProp(cur);
1077: cur = next;
1078: }
1079: }
1080:
1.23 daniel 1081: /**
1082: * xmlFreeProp:
1.83 daniel 1083: * @cur: an attribute
1.23 daniel 1084: *
1.83 daniel 1085: * Free one attribute, all the content is freed too
1.1 veillard 1086: */
1.28 daniel 1087: void
1088: xmlFreeProp(xmlAttrPtr cur) {
1.1 veillard 1089: if (cur == NULL) {
1.86 daniel 1090: #ifdef DEBUG_TREE
1.134 veillard 1091: xmlGenericError(xmlGenericErrorContext,
1092: "xmlFreeProp : property == NULL\n");
1.86 daniel 1093: #endif
1.1 veillard 1094: return;
1095: }
1.84 daniel 1096: /* Check for ID removal -> leading to invalid references ! */
1.90 daniel 1097: if ((cur->parent != NULL) &&
1098: (xmlIsID(cur->parent->doc, cur->parent, cur)))
1099: xmlRemoveID(cur->parent->doc, cur);
1.57 daniel 1100: if (cur->name != NULL) xmlFree((char *) cur->name);
1.90 daniel 1101: if (cur->children != NULL) xmlFreeNodeList(cur->children);
1.20 daniel 1102: memset(cur, -1, sizeof(xmlAttr));
1.57 daniel 1103: xmlFree(cur);
1.83 daniel 1104: }
1105:
1106: /**
1107: * xmlRemoveProp:
1108: * @cur: an attribute
1109: *
1110: * Unlink and free one attribute, all the content is freed too
1111: * Note this doesn't work for namespace definition attributes
1112: *
1113: * Returns 0 if success and -1 in case of error.
1114: */
1115: int
1116: xmlRemoveProp(xmlAttrPtr cur) {
1117: xmlAttrPtr tmp;
1118: if (cur == NULL) {
1.86 daniel 1119: #ifdef DEBUG_TREE
1.134 veillard 1120: xmlGenericError(xmlGenericErrorContext,
1121: "xmlRemoveProp : cur == NULL\n");
1.86 daniel 1122: #endif
1.83 daniel 1123: return(-1);
1124: }
1.90 daniel 1125: if (cur->parent == NULL) {
1.94 daniel 1126: #ifdef DEBUG_TREE
1.134 veillard 1127: xmlGenericError(xmlGenericErrorContext,
1128: "xmlRemoveProp : cur->parent == NULL\n");
1.86 daniel 1129: #endif
1.83 daniel 1130: return(-1);
1131: }
1.90 daniel 1132: tmp = cur->parent->properties;
1.83 daniel 1133: if (tmp == cur) {
1.90 daniel 1134: cur->parent->properties = cur->next;
1.83 daniel 1135: xmlFreeProp(cur);
1136: return(0);
1137: }
1138: while (tmp != NULL) {
1139: if (tmp->next == cur) {
1140: tmp->next = cur->next;
1.94 daniel 1141: if (tmp->next != NULL)
1142: tmp->next->prev = tmp;
1.83 daniel 1143: xmlFreeProp(cur);
1144: return(0);
1145: }
1146: tmp = tmp->next;
1147: }
1.86 daniel 1148: #ifdef DEBUG_TREE
1.134 veillard 1149: xmlGenericError(xmlGenericErrorContext,
1150: "xmlRemoveProp : attribute not owned by its node\n");
1.86 daniel 1151: #endif
1.83 daniel 1152: return(-1);
1.1 veillard 1153: }
1154:
1.23 daniel 1155: /**
1.52 daniel 1156: * xmlNewPI:
1157: * @name: the processing instruction name
1158: * @content: the PI content
1159: *
1160: * Creation of a processing instruction element.
1161: * Returns a pointer to the new node object.
1162: */
1163: xmlNodePtr
1.61 daniel 1164: xmlNewPI(const xmlChar *name, const xmlChar *content) {
1.52 daniel 1165: xmlNodePtr cur;
1166:
1167: if (name == NULL) {
1.86 daniel 1168: #ifdef DEBUG_TREE
1.134 veillard 1169: xmlGenericError(xmlGenericErrorContext,
1170: "xmlNewPI : name == NULL\n");
1.86 daniel 1171: #endif
1.52 daniel 1172: return(NULL);
1173: }
1174:
1175: /*
1176: * Allocate a new node and fill the fields.
1177: */
1.57 daniel 1178: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.52 daniel 1179: if (cur == NULL) {
1.134 veillard 1180: xmlGenericError(xmlGenericErrorContext,
1181: "xmlNewPI : malloc failed\n");
1.52 daniel 1182: return(NULL);
1183: }
1.90 daniel 1184: memset(cur, 0, sizeof(xmlNode));
1185: cur->type = XML_PI_NODE;
1.52 daniel 1186:
1187: cur->name = xmlStrdup(name);
1.70 daniel 1188: if (content != NULL) {
1189: #ifndef XML_USE_BUFFER_CONTENT
1.52 daniel 1190: cur->content = xmlStrdup(content);
1.70 daniel 1191: #else
1192: cur->content = xmlBufferCreateSize(0);
1193: xmlBufferSetAllocationScheme(cur->content,
1194: xmlGetBufferAllocationScheme());
1195: xmlBufferAdd(cur->content, content, -1);
1196: #endif
1.90 daniel 1197: }
1.52 daniel 1198: return(cur);
1199: }
1200:
1201: /**
1.23 daniel 1202: * xmlNewNode:
1203: * @ns: namespace if any
1204: * @name: the node name
1205: *
1.120 veillard 1206: * Creation of a new node element. @ns is optionnal (NULL).
1207: *
1.36 daniel 1208: * Returns a pointer to the new node object.
1.1 veillard 1209: */
1.28 daniel 1210: xmlNodePtr
1.61 daniel 1211: xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1.1 veillard 1212: xmlNodePtr cur;
1213:
1214: if (name == NULL) {
1.86 daniel 1215: #ifdef DEBUG_TREE
1.134 veillard 1216: xmlGenericError(xmlGenericErrorContext,
1217: "xmlNewNode : name == NULL\n");
1.86 daniel 1218: #endif
1.1 veillard 1219: return(NULL);
1220: }
1221:
1222: /*
1223: * Allocate a new node and fill the fields.
1224: */
1.57 daniel 1225: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.1 veillard 1226: if (cur == NULL) {
1.134 veillard 1227: xmlGenericError(xmlGenericErrorContext,
1228: "xmlNewNode : malloc failed\n");
1.1 veillard 1229: return(NULL);
1230: }
1.90 daniel 1231: memset(cur, 0, sizeof(xmlNode));
1.23 daniel 1232: cur->type = XML_ELEMENT_NODE;
1.90 daniel 1233:
1.22 daniel 1234: cur->name = xmlStrdup(name);
1.16 daniel 1235: cur->ns = ns;
1.1 veillard 1236: return(cur);
1237: }
1238:
1.23 daniel 1239: /**
1240: * xmlNewDocNode:
1241: * @doc: the document
1242: * @ns: namespace if any
1243: * @name: the node name
1.68 daniel 1244: * @content: the XML text content if any
1.23 daniel 1245: *
1246: * Creation of a new node element within a document. @ns and @content
1247: * are optionnal (NULL).
1.68 daniel 1248: * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1249: * references, but XML special chars need to be escaped first by using
1250: * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1251: * need entities support.
1252: *
1.36 daniel 1253: * Returns a pointer to the new node object.
1.23 daniel 1254: */
1.28 daniel 1255: xmlNodePtr
1256: xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1.68 daniel 1257: const xmlChar *name, const xmlChar *content) {
1.23 daniel 1258: xmlNodePtr cur;
1259:
1.24 daniel 1260: cur = xmlNewNode(ns, name);
1261: if (cur != NULL) {
1262: cur->doc = doc;
1.32 daniel 1263: if (content != NULL) {
1.90 daniel 1264: cur->children = xmlStringGetNodeList(doc, content);
1.140 veillard 1265: UPDATE_LAST_CHILD_AND_PARENT(cur)
1.32 daniel 1266: }
1.24 daniel 1267: }
1.23 daniel 1268: return(cur);
1269: }
1270:
1271:
1272: /**
1.68 daniel 1273: * xmlNewDocRawNode:
1274: * @doc: the document
1275: * @ns: namespace if any
1276: * @name: the node name
1277: * @content: the text content if any
1278: *
1279: * Creation of a new node element within a document. @ns and @content
1280: * are optionnal (NULL).
1281: *
1282: * Returns a pointer to the new node object.
1283: */
1284: xmlNodePtr
1285: xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1286: const xmlChar *name, const xmlChar *content) {
1287: xmlNodePtr cur;
1288:
1289: cur = xmlNewNode(ns, name);
1290: if (cur != NULL) {
1291: cur->doc = doc;
1292: if (content != NULL) {
1.90 daniel 1293: cur->children = xmlNewDocText(doc, content);
1.140 veillard 1294: UPDATE_LAST_CHILD_AND_PARENT(cur)
1.68 daniel 1295: }
1296: }
1297: return(cur);
1298: }
1299:
1.85 daniel 1300: /**
1301: * xmlNewDocFragment:
1302: * @doc: the document owning the fragment
1303: *
1304: * Creation of a new Fragment node.
1305: * Returns a pointer to the new node object.
1306: */
1307: xmlNodePtr
1308: xmlNewDocFragment(xmlDocPtr doc) {
1309: xmlNodePtr cur;
1310:
1311: /*
1312: * Allocate a new DocumentFragment node and fill the fields.
1313: */
1314: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1315: if (cur == NULL) {
1.134 veillard 1316: xmlGenericError(xmlGenericErrorContext,
1317: "xmlNewDocFragment : malloc failed\n");
1.85 daniel 1318: return(NULL);
1319: }
1.90 daniel 1320: memset(cur, 0, sizeof(xmlNode));
1321: cur->type = XML_DOCUMENT_FRAG_NODE;
1.85 daniel 1322:
1323: cur->doc = doc;
1324: return(cur);
1325: }
1.68 daniel 1326:
1327: /**
1.23 daniel 1328: * xmlNewText:
1329: * @content: the text content
1330: *
1331: * Creation of a new text node.
1.36 daniel 1332: * Returns a pointer to the new node object.
1.3 veillard 1333: */
1.28 daniel 1334: xmlNodePtr
1.61 daniel 1335: xmlNewText(const xmlChar *content) {
1.3 veillard 1336: xmlNodePtr cur;
1337:
1338: /*
1339: * Allocate a new node and fill the fields.
1340: */
1.57 daniel 1341: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.3 veillard 1342: if (cur == NULL) {
1.134 veillard 1343: xmlGenericError(xmlGenericErrorContext,
1344: "xmlNewText : malloc failed\n");
1.3 veillard 1345: return(NULL);
1346: }
1.90 daniel 1347: memset(cur, 0, sizeof(xmlNode));
1348: cur->type = XML_TEXT_NODE;
1.3 veillard 1349:
1.18 daniel 1350: cur->name = xmlStrdup(xmlStringText);
1.70 daniel 1351: if (content != NULL) {
1352: #ifndef XML_USE_BUFFER_CONTENT
1.7 veillard 1353: cur->content = xmlStrdup(content);
1.70 daniel 1354: #else
1355: cur->content = xmlBufferCreateSize(0);
1356: xmlBufferSetAllocationScheme(cur->content,
1357: xmlGetBufferAllocationScheme());
1358: xmlBufferAdd(cur->content, content, -1);
1359: #endif
1.90 daniel 1360: }
1.3 veillard 1361: return(cur);
1362: }
1363:
1.23 daniel 1364: /**
1.68 daniel 1365: * xmlNewTextChild:
1366: * @parent: the parent node
1367: * @ns: a namespace if any
1368: * @name: the name of the child
1369: * @content: the text content of the child if any.
1370: *
1.90 daniel 1371: * Creation of a new child element, added at the end of @parent children list.
1.68 daniel 1372: * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1373: * a child TEXT node will be created containing the string content.
1374: *
1375: * Returns a pointer to the new node object.
1376: */
1377: xmlNodePtr
1378: xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1379: const xmlChar *name, const xmlChar *content) {
1380: xmlNodePtr cur, prev;
1381:
1382: if (parent == NULL) {
1.86 daniel 1383: #ifdef DEBUG_TREE
1.134 veillard 1384: xmlGenericError(xmlGenericErrorContext,
1385: "xmlNewTextChild : parent == NULL\n");
1.86 daniel 1386: #endif
1.68 daniel 1387: return(NULL);
1388: }
1389:
1390: if (name == NULL) {
1.86 daniel 1391: #ifdef DEBUG_TREE
1.134 veillard 1392: xmlGenericError(xmlGenericErrorContext,
1393: "xmlNewTextChild : name == NULL\n");
1.86 daniel 1394: #endif
1.68 daniel 1395: return(NULL);
1396: }
1397:
1398: /*
1399: * Allocate a new node
1400: */
1401: if (ns == NULL)
1402: cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1403: else
1404: cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1405: if (cur == NULL) return(NULL);
1406:
1407: /*
1.90 daniel 1408: * add the new element at the end of the children list.
1.68 daniel 1409: */
1410: cur->type = XML_ELEMENT_NODE;
1411: cur->parent = parent;
1412: cur->doc = parent->doc;
1.90 daniel 1413: if (parent->children == NULL) {
1414: parent->children = cur;
1.68 daniel 1415: parent->last = cur;
1416: } else {
1417: prev = parent->last;
1418: prev->next = cur;
1419: cur->prev = prev;
1420: parent->last = cur;
1421: }
1422:
1423: return(cur);
1424: }
1425:
1426: /**
1.88 daniel 1427: * xmlNewCharRef:
1428: * @doc: the document
1429: * @name: the char ref string, starting with # or "&# ... ;"
1430: *
1431: * Creation of a new character reference node.
1432: * Returns a pointer to the new node object.
1433: */
1434: xmlNodePtr
1435: xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1436: xmlNodePtr cur;
1437:
1438: /*
1439: * Allocate a new node and fill the fields.
1440: */
1441: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1442: if (cur == NULL) {
1.134 veillard 1443: xmlGenericError(xmlGenericErrorContext,
1444: "xmlNewText : malloc failed\n");
1.88 daniel 1445: return(NULL);
1446: }
1.90 daniel 1447: memset(cur, 0, sizeof(xmlNode));
1448: cur->type = XML_ENTITY_REF_NODE;
1.88 daniel 1449:
1450: cur->doc = doc;
1451: if (name[0] == '&') {
1452: int len;
1453: name++;
1454: len = xmlStrlen(name);
1455: if (name[len - 1] == ';')
1456: cur->name = xmlStrndup(name, len - 1);
1457: else
1458: cur->name = xmlStrndup(name, len);
1459: } else
1460: cur->name = xmlStrdup(name);
1461: return(cur);
1462: }
1463:
1464: /**
1.23 daniel 1465: * xmlNewReference:
1466: * @doc: the document
1467: * @name: the reference name, or the reference string with & and ;
1468: *
1469: * Creation of a new reference node.
1.36 daniel 1470: * Returns a pointer to the new node object.
1.23 daniel 1471: */
1.28 daniel 1472: xmlNodePtr
1.61 daniel 1473: xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1.23 daniel 1474: xmlNodePtr cur;
1475: xmlEntityPtr ent;
1476:
1477: /*
1478: * Allocate a new node and fill the fields.
1479: */
1.57 daniel 1480: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.23 daniel 1481: if (cur == NULL) {
1.134 veillard 1482: xmlGenericError(xmlGenericErrorContext,
1483: "xmlNewText : malloc failed\n");
1.23 daniel 1484: return(NULL);
1485: }
1.90 daniel 1486: memset(cur, 0, sizeof(xmlNode));
1487: cur->type = XML_ENTITY_REF_NODE;
1.23 daniel 1488:
1.28 daniel 1489: cur->doc = doc;
1.23 daniel 1490: if (name[0] == '&') {
1491: int len;
1492: name++;
1493: len = xmlStrlen(name);
1494: if (name[len - 1] == ';')
1495: cur->name = xmlStrndup(name, len - 1);
1496: else
1497: cur->name = xmlStrndup(name, len);
1498: } else
1499: cur->name = xmlStrdup(name);
1500:
1501: ent = xmlGetDocEntity(doc, cur->name);
1.70 daniel 1502: if (ent != NULL) {
1503: #ifndef XML_USE_BUFFER_CONTENT
1.23 daniel 1504: cur->content = ent->content;
1.70 daniel 1505: #else
1506: /*
1507: * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1508: * a copy of this pointer. Let's hope we don't manipulate it
1509: * later
1510: */
1511: cur->content = xmlBufferCreateSize(0);
1512: xmlBufferSetAllocationScheme(cur->content,
1513: xmlGetBufferAllocationScheme());
1514: if (ent->content != NULL)
1515: xmlBufferAdd(cur->content, ent->content, -1);
1516: #endif
1.140 veillard 1517: /*
1518: * The parent pointer in entity is a Dtd pointer and thus is NOT
1519: * updated. Not sure if this is 100% correct.
1520: * -George
1521: */
1.99 daniel 1522: cur->children = (xmlNodePtr) ent;
1.140 veillard 1523: cur->last = (xmlNodePtr) ent;
1.90 daniel 1524: }
1.23 daniel 1525: return(cur);
1526: }
1527:
1528: /**
1529: * xmlNewDocText:
1530: * @doc: the document
1531: * @content: the text content
1532: *
1533: * Creation of a new text node within a document.
1.36 daniel 1534: * Returns a pointer to the new node object.
1.23 daniel 1535: */
1.28 daniel 1536: xmlNodePtr
1.61 daniel 1537: xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1.23 daniel 1538: xmlNodePtr cur;
1539:
1540: cur = xmlNewText(content);
1541: if (cur != NULL) cur->doc = doc;
1542: return(cur);
1543: }
1544:
1545: /**
1546: * xmlNewTextLen:
1547: * @content: the text content
1548: * @len: the text len.
1549: *
1550: * Creation of a new text node with an extra parameter for the content's lenght
1.36 daniel 1551: * Returns a pointer to the new node object.
1.21 daniel 1552: */
1.28 daniel 1553: xmlNodePtr
1.61 daniel 1554: xmlNewTextLen(const xmlChar *content, int len) {
1.21 daniel 1555: xmlNodePtr cur;
1556:
1557: /*
1558: * Allocate a new node and fill the fields.
1559: */
1.57 daniel 1560: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.21 daniel 1561: if (cur == NULL) {
1.134 veillard 1562: xmlGenericError(xmlGenericErrorContext,
1563: "xmlNewText : malloc failed\n");
1.21 daniel 1564: return(NULL);
1565: }
1.90 daniel 1566: memset(cur, 0, sizeof(xmlNode));
1567: cur->type = XML_TEXT_NODE;
1.21 daniel 1568:
1569: cur->name = xmlStrdup(xmlStringText);
1.70 daniel 1570: if (content != NULL) {
1571: #ifndef XML_USE_BUFFER_CONTENT
1.21 daniel 1572: cur->content = xmlStrndup(content, len);
1.70 daniel 1573: #else
1574: cur->content = xmlBufferCreateSize(len);
1575: xmlBufferSetAllocationScheme(cur->content,
1576: xmlGetBufferAllocationScheme());
1577: xmlBufferAdd(cur->content, content, len);
1578: #endif
1.90 daniel 1579: }
1.21 daniel 1580: return(cur);
1581: }
1582:
1.23 daniel 1583: /**
1584: * xmlNewDocTextLen:
1585: * @doc: the document
1586: * @content: the text content
1587: * @len: the text len.
1588: *
1589: * Creation of a new text node with an extra content lenght parameter. The
1590: * text node pertain to a given document.
1.36 daniel 1591: * Returns a pointer to the new node object.
1.23 daniel 1592: */
1.28 daniel 1593: xmlNodePtr
1.61 daniel 1594: xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1.23 daniel 1595: xmlNodePtr cur;
1596:
1597: cur = xmlNewTextLen(content, len);
1598: if (cur != NULL) cur->doc = doc;
1599: return(cur);
1600: }
1601:
1602: /**
1603: * xmlNewComment:
1604: * @content: the comment content
1605: *
1606: * Creation of a new node containing a comment.
1.36 daniel 1607: * Returns a pointer to the new node object.
1.14 daniel 1608: */
1.28 daniel 1609: xmlNodePtr
1.61 daniel 1610: xmlNewComment(const xmlChar *content) {
1.14 daniel 1611: xmlNodePtr cur;
1612:
1613: /*
1614: * Allocate a new node and fill the fields.
1615: */
1.57 daniel 1616: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.14 daniel 1617: if (cur == NULL) {
1.134 veillard 1618: xmlGenericError(xmlGenericErrorContext,
1619: "xmlNewComment : malloc failed\n");
1.14 daniel 1620: return(NULL);
1621: }
1.90 daniel 1622: memset(cur, 0, sizeof(xmlNode));
1623: cur->type = XML_COMMENT_NODE;
1.14 daniel 1624:
1.90 daniel 1625: cur->name = xmlStrdup(xmlStringComment);
1.70 daniel 1626: if (content != NULL) {
1627: #ifndef XML_USE_BUFFER_CONTENT
1.14 daniel 1628: cur->content = xmlStrdup(content);
1.70 daniel 1629: #else
1630: cur->content = xmlBufferCreateSize(0);
1631: xmlBufferSetAllocationScheme(cur->content,
1632: xmlGetBufferAllocationScheme());
1633: xmlBufferAdd(cur->content, content, -1);
1634: #endif
1.90 daniel 1635: }
1.14 daniel 1636: return(cur);
1637: }
1638:
1.23 daniel 1639: /**
1.50 daniel 1640: * xmlNewCDataBlock:
1641: * @doc: the document
1642: * @content: the CData block content content
1643: * @len: the length of the block
1644: *
1645: * Creation of a new node containing a CData block.
1646: * Returns a pointer to the new node object.
1647: */
1648: xmlNodePtr
1.61 daniel 1649: xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1.50 daniel 1650: xmlNodePtr cur;
1651:
1652: /*
1653: * Allocate a new node and fill the fields.
1654: */
1.57 daniel 1655: cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.50 daniel 1656: if (cur == NULL) {
1.134 veillard 1657: xmlGenericError(xmlGenericErrorContext,
1658: "xmlNewCDataBlock : malloc failed\n");
1.50 daniel 1659: return(NULL);
1660: }
1.90 daniel 1661: memset(cur, 0, sizeof(xmlNode));
1662: cur->type = XML_CDATA_SECTION_NODE;
1.50 daniel 1663:
1.70 daniel 1664: if (content != NULL) {
1665: #ifndef XML_USE_BUFFER_CONTENT
1.50 daniel 1666: cur->content = xmlStrndup(content, len);
1.70 daniel 1667: #else
1668: cur->content = xmlBufferCreateSize(len);
1669: xmlBufferSetAllocationScheme(cur->content,
1670: xmlGetBufferAllocationScheme());
1671: xmlBufferAdd(cur->content, content, len);
1672: #endif
1.90 daniel 1673: }
1.50 daniel 1674: return(cur);
1675: }
1676:
1677: /**
1.36 daniel 1678: * xmlNewDocComment:
1.23 daniel 1679: * @doc: the document
1680: * @content: the comment content
1681: *
1682: * Creation of a new node containing a commentwithin a document.
1.36 daniel 1683: * Returns a pointer to the new node object.
1.23 daniel 1684: */
1.28 daniel 1685: xmlNodePtr
1.61 daniel 1686: xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1.23 daniel 1687: xmlNodePtr cur;
1688:
1689: cur = xmlNewComment(content);
1690: if (cur != NULL) cur->doc = doc;
1691: return(cur);
1692: }
1693:
1.141 veillard 1694: /**
1695: * xmlSetTreeDoc:
1696: * @tree: the top element
1697: * @doc: the document
1698: *
1699: * update all nodes under the tree to point to the right document
1700: */
1701: void
1702: xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1703: if (tree == NULL)
1704: return;
1705: if (tree->type == XML_ENTITY_DECL)
1706: return;
1707: if (tree->doc != doc) {
1708: if (tree->children != NULL)
1709: xmlSetListDoc(tree->children, doc);
1710: tree->doc = doc;
1711: }
1712: }
1713:
1714: /**
1715: * xmlSetListDoc:
1716: * @tree: the first element
1717: * @doc: the document
1718: *
1719: * update all nodes in the list to point to the right document
1720: */
1721: void
1722: xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1723: xmlNodePtr cur;
1724:
1725: if (list == NULL)
1726: return;
1727: cur = list;
1728: while (cur != NULL) {
1729: if (cur->doc != doc)
1730: xmlSetTreeDoc(cur, doc);
1731: cur = cur->next;
1732: }
1733: }
1734:
1.68 daniel 1735:
1.23 daniel 1736: /**
1737: * xmlNewChild:
1738: * @parent: the parent node
1739: * @ns: a namespace if any
1740: * @name: the name of the child
1.68 daniel 1741: * @content: the XML content of the child if any.
1.23 daniel 1742: *
1.90 daniel 1743: * Creation of a new child element, added at the end of @parent children list.
1.24 daniel 1744: * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1745: * a child list containing the TEXTs and ENTITY_REFs node will be created.
1.68 daniel 1746: * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1747: * references, but XML special chars need to be escaped first by using
1748: * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1749: * support is not needed.
1750: *
1.36 daniel 1751: * Returns a pointer to the new node object.
1.1 veillard 1752: */
1.28 daniel 1753: xmlNodePtr
1754: xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1.68 daniel 1755: const xmlChar *name, const xmlChar *content) {
1.1 veillard 1756: xmlNodePtr cur, prev;
1757:
1758: if (parent == NULL) {
1.86 daniel 1759: #ifdef DEBUG_TREE
1.134 veillard 1760: xmlGenericError(xmlGenericErrorContext,
1761: "xmlNewChild : parent == NULL\n");
1.86 daniel 1762: #endif
1.1 veillard 1763: return(NULL);
1764: }
1765:
1766: if (name == NULL) {
1.86 daniel 1767: #ifdef DEBUG_TREE
1.134 veillard 1768: xmlGenericError(xmlGenericErrorContext,
1769: "xmlNewChild : name == NULL\n");
1.86 daniel 1770: #endif
1.1 veillard 1771: return(NULL);
1772: }
1773:
1774: /*
1775: * Allocate a new node
1776: */
1.16 daniel 1777: if (ns == NULL)
1.24 daniel 1778: cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1.1 veillard 1779: else
1.24 daniel 1780: cur = xmlNewDocNode(parent->doc, ns, name, content);
1.1 veillard 1781: if (cur == NULL) return(NULL);
1782:
1783: /*
1.90 daniel 1784: * add the new element at the end of the children list.
1.1 veillard 1785: */
1.25 daniel 1786: cur->type = XML_ELEMENT_NODE;
1.1 veillard 1787: cur->parent = parent;
1.23 daniel 1788: cur->doc = parent->doc;
1.90 daniel 1789: if (parent->children == NULL) {
1790: parent->children = cur;
1.32 daniel 1791: parent->last = cur;
1.1 veillard 1792: } else {
1.32 daniel 1793: prev = parent->last;
1.1 veillard 1794: prev->next = cur;
1.23 daniel 1795: cur->prev = prev;
1.32 daniel 1796: parent->last = cur;
1.1 veillard 1797: }
1798:
1799: return(cur);
1800: }
1801:
1.23 daniel 1802: /**
1.78 daniel 1803: * xmlAddNextSibling:
1804: * @cur: the child node
1805: * @elem: the new node
1806: *
1807: * Add a new element @elem as the next siblings of @cur
1808: * If the new element was already inserted in a document it is
1809: * first unlinked from its existing context.
1.131 veillard 1810: * As a result of text merging @elem may be freed.
1.78 daniel 1811: *
1812: * Returns the new element or NULL in case of error.
1813: */
1814: xmlNodePtr
1815: xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1816: if (cur == NULL) {
1.86 daniel 1817: #ifdef DEBUG_TREE
1.134 veillard 1818: xmlGenericError(xmlGenericErrorContext,
1819: "xmlAddNextSibling : cur == NULL\n");
1.86 daniel 1820: #endif
1.78 daniel 1821: return(NULL);
1822: }
1823: if (elem == NULL) {
1.86 daniel 1824: #ifdef DEBUG_TREE
1.134 veillard 1825: xmlGenericError(xmlGenericErrorContext,
1826: "xmlAddNextSibling : elem == NULL\n");
1.86 daniel 1827: #endif
1.78 daniel 1828: return(NULL);
1829: }
1830:
1831: xmlUnlinkNode(elem);
1.131 veillard 1832:
1833: if (elem->type == XML_TEXT_NODE) {
1834: if (cur->type == XML_TEXT_NODE) {
1835: #ifndef XML_USE_BUFFER_CONTENT
1836: xmlNodeAddContent(cur, elem->content);
1837: #else
1838: xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1839: #endif
1840: xmlFreeNode(elem);
1841: return(cur);
1842: }
1843: if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1844: #ifndef XML_USE_BUFFER_CONTENT
1845: xmlChar *tmp;
1846:
1847: tmp = xmlStrdup(elem->content);
1848: tmp = xmlStrcat(tmp, cur->next->content);
1849: xmlNodeSetContent(cur->next, tmp);
1850: xmlFree(tmp);
1851: #else
1.137 veillard 1852: xmlBufferAddHead(cur->next->content,
1853: xmlBufferContent(elem->content),
1.131 veillard 1854: xmlBufferLength(elem->content));
1855: #endif
1856: xmlFreeNode(elem);
1857: return(cur->next);
1858: }
1859: }
1860:
1.141 veillard 1861: if (elem->doc != cur->doc) {
1862: xmlSetTreeDoc(elem, cur->doc);
1863: }
1.78 daniel 1864: elem->parent = cur->parent;
1.102 daniel 1865: elem->prev = cur;
1866: elem->next = cur->next;
1867: cur->next = elem;
1868: if (elem->next != NULL)
1869: elem->next->prev = elem;
1870: if ((elem->parent != NULL) && (elem->parent->last == cur))
1871: elem->parent->last = elem;
1.78 daniel 1872: return(elem);
1873: }
1874:
1875: /**
1876: * xmlAddPrevSibling:
1877: * @cur: the child node
1878: * @elem: the new node
1879: *
1880: * Add a new element @elem as the previous siblings of @cur
1.131 veillard 1881: * merging adjacent TEXT nodes (@elem may be freed)
1.78 daniel 1882: * If the new element was already inserted in a document it is
1883: * first unlinked from its existing context.
1884: *
1885: * Returns the new element or NULL in case of error.
1886: */
1887: xmlNodePtr
1888: xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1889: if (cur == NULL) {
1.86 daniel 1890: #ifdef DEBUG_TREE
1.134 veillard 1891: xmlGenericError(xmlGenericErrorContext,
1892: "xmlAddPrevSibling : cur == NULL\n");
1.86 daniel 1893: #endif
1.78 daniel 1894: return(NULL);
1895: }
1896: if (elem == NULL) {
1.86 daniel 1897: #ifdef DEBUG_TREE
1.134 veillard 1898: xmlGenericError(xmlGenericErrorContext,
1899: "xmlAddPrevSibling : elem == NULL\n");
1.86 daniel 1900: #endif
1.78 daniel 1901: return(NULL);
1902: }
1903:
1904: xmlUnlinkNode(elem);
1.131 veillard 1905:
1906: if (elem->type == XML_TEXT_NODE) {
1907: if (cur->type == XML_TEXT_NODE) {
1908: #ifndef XML_USE_BUFFER_CONTENT
1909: xmlChar *tmp;
1910:
1911: tmp = xmlStrdup(elem->content);
1912: tmp = xmlStrcat(tmp, cur->content);
1913: xmlNodeSetContent(cur, tmp);
1914: xmlFree(tmp);
1915: #else
1916: xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1917: xmlBufferLength(elem->content));
1918: #endif
1919: xmlFreeNode(elem);
1920: return(cur);
1921: }
1922: if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1923: #ifndef XML_USE_BUFFER_CONTENT
1924: xmlNodeAddContent(cur->prev, elem->content);
1925: #else
1926: xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1927: #endif
1928: xmlFreeNode(elem);
1929: return(cur->prev);
1930: }
1931: }
1932:
1.141 veillard 1933: if (elem->doc != cur->doc) {
1934: xmlSetTreeDoc(elem, cur->doc);
1935: }
1.78 daniel 1936: elem->parent = cur->parent;
1.102 daniel 1937: elem->next = cur;
1938: elem->prev = cur->prev;
1939: cur->prev = elem;
1940: if (elem->prev != NULL)
1941: elem->prev->next = elem;
1942: if ((elem->parent != NULL) && (elem->parent->children == cur))
1943: elem->parent->children = elem;
1.78 daniel 1944: return(elem);
1945: }
1946:
1947: /**
1.52 daniel 1948: * xmlAddSibling:
1949: * @cur: the child node
1950: * @elem: the new node
1951: *
1.78 daniel 1952: * Add a new element @elem to the list of siblings of @cur
1.131 veillard 1953: * merging adjacent TEXT nodes (@elem may be freed)
1.78 daniel 1954: * If the new element was already inserted in a document it is
1955: * first unlinked from its existing context.
1956: *
1957: * Returns the new element or NULL in case of error.
1.52 daniel 1958: */
1959: xmlNodePtr
1960: xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1961: xmlNodePtr parent;
1962:
1963: if (cur == NULL) {
1.86 daniel 1964: #ifdef DEBUG_TREE
1.134 veillard 1965: xmlGenericError(xmlGenericErrorContext,
1966: "xmlAddSibling : cur == NULL\n");
1.86 daniel 1967: #endif
1.52 daniel 1968: return(NULL);
1969: }
1970:
1971: if (elem == NULL) {
1.86 daniel 1972: #ifdef DEBUG_TREE
1.134 veillard 1973: xmlGenericError(xmlGenericErrorContext,
1974: "xmlAddSibling : elem == NULL\n");
1.86 daniel 1975: #endif
1.52 daniel 1976: return(NULL);
1977: }
1978:
1.78 daniel 1979: /*
1980: * Constant time is we can rely on the ->parent->last to find
1981: * the last sibling.
1982: */
1983: if ((cur->parent != NULL) &&
1.90 daniel 1984: (cur->parent->children != NULL) &&
1.78 daniel 1985: (cur->parent->last != NULL) &&
1986: (cur->parent->last->next == NULL)) {
1987: cur = cur->parent->last;
1988: } else {
1989: while (cur->next != NULL) cur = cur->next;
1.52 daniel 1990: }
1991:
1.78 daniel 1992: xmlUnlinkNode(elem);
1.131 veillard 1993:
1994: if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
1995: #ifndef XML_USE_BUFFER_CONTENT
1996: xmlNodeAddContent(cur, elem->content);
1997: #else
1998: xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1999: #endif
2000: xmlFreeNode(elem);
2001: return(cur);
2002: }
2003:
1.141 veillard 2004: if (elem->doc != cur->doc) {
2005: xmlSetTreeDoc(elem, cur->doc);
2006: }
1.52 daniel 2007: parent = cur->parent;
2008: elem->prev = cur;
2009: elem->next = NULL;
2010: elem->parent = parent;
2011: cur->next = elem;
2012: if (parent != NULL)
2013: parent->last = elem;
2014:
2015: return(elem);
2016: }
2017:
2018: /**
1.117 veillard 2019: * xmlAddChildList:
2020: * @parent: the parent node
2021: * @cur: the first node in the list
2022: *
2023: * Add a list of node at the end of the child list of the parent
1.131 veillard 2024: * merging adjacent TEXT nodes (@cur may be freed)
1.117 veillard 2025: *
2026: * Returns the last child or NULL in case of error.
2027: */
2028: xmlNodePtr
2029: xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2030: xmlNodePtr prev;
2031:
2032: if (parent == NULL) {
2033: #ifdef DEBUG_TREE
1.134 veillard 2034: xmlGenericError(xmlGenericErrorContext,
2035: "xmlAddChild : parent == NULL\n");
1.117 veillard 2036: #endif
2037: return(NULL);
2038: }
2039:
2040: if (cur == NULL) {
2041: #ifdef DEBUG_TREE
1.134 veillard 2042: xmlGenericError(xmlGenericErrorContext,
2043: "xmlAddChild : child == NULL\n");
1.117 veillard 2044: #endif
2045: return(NULL);
2046: }
2047:
2048: if ((cur->doc != NULL) && (parent->doc != NULL) &&
2049: (cur->doc != parent->doc)) {
2050: #ifdef DEBUG_TREE
1.134 veillard 2051: xmlGenericError(xmlGenericErrorContext,
2052: "Elements moved to a different document\n");
1.117 veillard 2053: #endif
2054: }
2055:
2056: /*
2057: * add the first element at the end of the children list.
2058: */
2059: if (parent->children == NULL) {
2060: parent->children = cur;
2061: } else {
1.131 veillard 2062: /*
2063: * If cur and parent->last both are TEXT nodes, then merge them.
2064: */
2065: if ((cur->type == XML_TEXT_NODE) &&
2066: (parent->last->type == XML_TEXT_NODE)) {
2067: #ifndef XML_USE_BUFFER_CONTENT
2068: xmlNodeAddContent(parent->last, cur->content);
2069: #else
2070: xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2071: #endif
2072: /*
2073: * if it's the only child, nothing more to be done.
2074: */
2075: if (cur->next == NULL) {
2076: xmlFreeNode(cur);
2077: return(parent->last);
2078: }
2079: prev = cur;
2080: cur = cur->next;
2081: xmlFreeNode(prev);
2082: }
1.117 veillard 2083: prev = parent->last;
2084: prev->next = cur;
2085: cur->prev = prev;
2086: }
2087: while (cur->next != NULL) {
2088: cur->parent = parent;
1.141 veillard 2089: if (cur->doc != parent->doc) {
2090: xmlSetTreeDoc(cur, parent->doc);
2091: }
1.117 veillard 2092: cur = cur->next;
2093: }
2094: cur->parent = parent;
2095: cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2096: parent->last = cur;
2097:
2098: return(cur);
2099: }
2100:
2101: /**
1.23 daniel 2102: * xmlAddChild:
2103: * @parent: the parent node
2104: * @cur: the child node
2105: *
1.131 veillard 2106: * Add a new child element, to @parent, at the end of the child list
2107: * merging adjacent TEXT nodes (in which case @cur is freed)
1.36 daniel 2108: * Returns the child or NULL in case of error.
1.2 veillard 2109: */
1.28 daniel 2110: xmlNodePtr
2111: xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
1.2 veillard 2112: xmlNodePtr prev;
2113:
2114: if (parent == NULL) {
1.86 daniel 2115: #ifdef DEBUG_TREE
1.134 veillard 2116: xmlGenericError(xmlGenericErrorContext,
2117: "xmlAddChild : parent == NULL\n");
1.86 daniel 2118: #endif
1.2 veillard 2119: return(NULL);
2120: }
2121:
2122: if (cur == NULL) {
1.86 daniel 2123: #ifdef DEBUG_TREE
1.134 veillard 2124: xmlGenericError(xmlGenericErrorContext,
2125: "xmlAddChild : child == NULL\n");
1.86 daniel 2126: #endif
1.2 veillard 2127: return(NULL);
2128: }
2129:
1.23 daniel 2130: if ((cur->doc != NULL) && (parent->doc != NULL) &&
2131: (cur->doc != parent->doc)) {
1.86 daniel 2132: #ifdef DEBUG_TREE
1.134 veillard 2133: xmlGenericError(xmlGenericErrorContext,
2134: "Elements moved to a different document\n");
1.86 daniel 2135: #endif
1.131 veillard 2136: }
2137:
2138: /*
2139: * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2140: * or with parent->content if parent->content != NULL.
2141: * cur is then freed.
2142: */
2143: if (cur->type == XML_TEXT_NODE) {
2144: if (((parent->type == XML_ELEMENT_NODE) ||
2145: (parent->type == XML_TEXT_NODE)) &&
2146: (parent->content != NULL)) {
2147: #ifndef XML_USE_BUFFER_CONTENT
2148: xmlNodeAddContent(parent, cur->content);
2149: #else
2150: xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2151: #endif
2152: xmlFreeNode(cur);
2153: return(parent);
2154: }
2155: if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE)) {
2156: #ifndef XML_USE_BUFFER_CONTENT
2157: xmlNodeAddContent(parent->last, cur->content);
2158: #else
2159: xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2160: #endif
2161: xmlFreeNode(cur);
2162: return(parent->last);
2163: }
1.23 daniel 2164: }
2165:
1.2 veillard 2166: /*
1.90 daniel 2167: * add the new element at the end of the children list.
1.2 veillard 2168: */
2169: cur->parent = parent;
1.141 veillard 2170: if (cur->doc != parent->doc) {
2171: xmlSetTreeDoc(cur, parent->doc);
2172: }
1.32 daniel 2173:
1.24 daniel 2174: /*
2175: * Handle the case where parent->content != NULL, in that case it will
2176: * create a intermediate TEXT node.
2177: */
1.93 daniel 2178: if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2179: (parent->content != NULL)) {
1.24 daniel 2180: xmlNodePtr text;
2181:
1.70 daniel 2182: #ifndef XML_USE_BUFFER_CONTENT
1.24 daniel 2183: text = xmlNewDocText(parent->doc, parent->content);
1.70 daniel 2184: #else
2185: text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2186: #endif
1.24 daniel 2187: if (text != NULL) {
1.90 daniel 2188: text->next = parent->children;
1.24 daniel 2189: if (text->next != NULL)
2190: text->next->prev = text;
1.90 daniel 2191: parent->children = text;
1.140 veillard 2192: UPDATE_LAST_CHILD_AND_PARENT(parent)
1.70 daniel 2193: #ifndef XML_USE_BUFFER_CONTENT
1.57 daniel 2194: xmlFree(parent->content);
1.70 daniel 2195: #else
2196: xmlBufferFree(parent->content);
2197: #endif
1.24 daniel 2198: parent->content = NULL;
2199: }
2200: }
1.90 daniel 2201: if (parent->children == NULL) {
2202: parent->children = cur;
1.32 daniel 2203: parent->last = cur;
1.2 veillard 2204: } else {
1.32 daniel 2205: prev = parent->last;
1.2 veillard 2206: prev->next = cur;
1.23 daniel 2207: cur->prev = prev;
1.32 daniel 2208: parent->last = cur;
1.2 veillard 2209: }
2210:
2211: return(cur);
2212: }
2213:
1.23 daniel 2214: /**
2215: * xmlGetLastChild:
2216: * @parent: the parent node
2217: *
2218: * Search the last child of a node.
1.36 daniel 2219: * Returns the last child or NULL if none.
1.21 daniel 2220: */
1.28 daniel 2221: xmlNodePtr
2222: xmlGetLastChild(xmlNodePtr parent) {
1.21 daniel 2223: if (parent == NULL) {
1.86 daniel 2224: #ifdef DEBUG_TREE
1.134 veillard 2225: xmlGenericError(xmlGenericErrorContext,
2226: "xmlGetLastChild : parent == NULL\n");
1.86 daniel 2227: #endif
1.21 daniel 2228: return(NULL);
2229: }
1.32 daniel 2230: return(parent->last);
1.21 daniel 2231: }
2232:
1.23 daniel 2233: /**
2234: * xmlFreeNodeList:
2235: * @cur: the first node in the list
2236: *
2237: * Free a node and all its siblings, this is a recursive behaviour, all
1.90 daniel 2238: * the children are freed too.
1.1 veillard 2239: */
1.28 daniel 2240: void
2241: xmlFreeNodeList(xmlNodePtr cur) {
1.1 veillard 2242: xmlNodePtr next;
2243: if (cur == NULL) {
1.86 daniel 2244: #ifdef DEBUG_TREE
1.134 veillard 2245: xmlGenericError(xmlGenericErrorContext,
2246: "xmlFreeNodeList : node == NULL\n");
1.86 daniel 2247: #endif
1.1 veillard 2248: return;
2249: }
2250: while (cur != NULL) {
2251: next = cur->next;
2252: xmlFreeNode(cur);
2253: cur = next;
2254: }
2255: }
2256:
1.23 daniel 2257: /**
2258: * xmlFreeNode:
2259: * @cur: the node
2260: *
1.90 daniel 2261: * Free a node, this is a recursive behaviour, all the children are freed too.
1.97 daniel 2262: * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
1.1 veillard 2263: */
1.28 daniel 2264: void
2265: xmlFreeNode(xmlNodePtr cur) {
1.1 veillard 2266: if (cur == NULL) {
1.86 daniel 2267: #ifdef DEBUG_TREE
1.134 veillard 2268: xmlGenericError(xmlGenericErrorContext,
2269: "xmlFreeNode : node == NULL\n");
1.86 daniel 2270: #endif
1.1 veillard 2271: return;
2272: }
1.92 daniel 2273: if (cur->type == XML_DTD_NODE)
2274: return;
1.23 daniel 2275: cur->doc = NULL;
2276: cur->parent = NULL;
2277: cur->next = NULL;
2278: cur->prev = NULL;
1.99 daniel 2279: if ((cur->children != NULL) &&
2280: (cur->type != XML_ENTITY_REF_NODE))
2281: xmlFreeNodeList(cur->children);
1.1 veillard 2282: if (cur->properties != NULL) xmlFreePropList(cur->properties);
1.23 daniel 2283: if (cur->type != XML_ENTITY_REF_NODE)
1.70 daniel 2284: #ifndef XML_USE_BUFFER_CONTENT
1.57 daniel 2285: if (cur->content != NULL) xmlFree(cur->content);
1.70 daniel 2286: #else
2287: if (cur->content != NULL) xmlBufferFree(cur->content);
2288: #endif
1.57 daniel 2289: if (cur->name != NULL) xmlFree((char *) cur->name);
1.19 daniel 2290: if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1.1 veillard 2291: memset(cur, -1, sizeof(xmlNode));
1.57 daniel 2292: xmlFree(cur);
1.1 veillard 2293: }
2294:
1.28 daniel 2295: /**
2296: * xmlUnlinkNode:
2297: * @cur: the node
2298: *
2299: * Unlink a node from it's current context, the node is not freed
2300: */
2301: void
2302: xmlUnlinkNode(xmlNodePtr cur) {
2303: if (cur == NULL) {
1.86 daniel 2304: #ifdef DEBUG_TREE
1.134 veillard 2305: xmlGenericError(xmlGenericErrorContext,
2306: "xmlUnlinkNode : node == NULL\n");
1.86 daniel 2307: #endif
1.28 daniel 2308: return;
2309: }
1.90 daniel 2310: if ((cur->parent != NULL) && (cur->parent->children == cur))
2311: cur->parent->children = cur->next;
1.32 daniel 2312: if ((cur->parent != NULL) && (cur->parent->last == cur))
2313: cur->parent->last = cur->prev;
1.28 daniel 2314: if (cur->next != NULL)
2315: cur->next->prev = cur->prev;
2316: if (cur->prev != NULL)
2317: cur->prev->next = cur->next;
2318: cur->next = cur->prev = NULL;
2319: cur->parent = NULL;
2320: }
2321:
1.78 daniel 2322: /**
2323: * xmlReplaceNode:
2324: * @old: the old node
2325: * @cur: the node
2326: *
2327: * Unlink the old node from it's current context, prune the new one
2328: * at the same place. If cur was already inserted in a document it is
2329: * first unlinked from its existing context.
2330: *
2331: * Returns the old node
2332: */
2333: xmlNodePtr
2334: xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2335: if (old == NULL) {
1.86 daniel 2336: #ifdef DEBUG_TREE
1.134 veillard 2337: xmlGenericError(xmlGenericErrorContext,
2338: "xmlReplaceNode : old == NULL\n");
1.86 daniel 2339: #endif
1.78 daniel 2340: return(NULL);
2341: }
2342: if (cur == NULL) {
2343: xmlUnlinkNode(old);
2344: return(old);
2345: }
1.140 veillard 2346: if (cur == old) {
2347: return(old);
2348: }
1.78 daniel 2349: xmlUnlinkNode(cur);
2350: cur->doc = old->doc;
2351: cur->parent = old->parent;
2352: cur->next = old->next;
2353: if (cur->next != NULL)
2354: cur->next->prev = cur;
2355: cur->prev = old->prev;
2356: if (cur->prev != NULL)
2357: cur->prev->next = cur;
2358: if (cur->parent != NULL) {
1.90 daniel 2359: if (cur->parent->children == old)
2360: cur->parent->children = cur;
1.78 daniel 2361: if (cur->parent->last == old)
2362: cur->parent->last = cur;
2363: }
2364: old->next = old->prev = NULL;
2365: old->parent = NULL;
2366: return(old);
2367: }
2368:
1.1 veillard 2369: /************************************************************************
2370: * *
1.31 daniel 2371: * Copy operations *
2372: * *
2373: ************************************************************************/
2374:
2375: /**
2376: * xmlCopyNamespace:
2377: * @cur: the namespace
2378: *
2379: * Do a copy of the namespace.
2380: *
2381: * Returns: a new xmlNsPtr, or NULL in case of error.
2382: */
2383: xmlNsPtr
2384: xmlCopyNamespace(xmlNsPtr cur) {
2385: xmlNsPtr ret;
2386:
2387: if (cur == NULL) return(NULL);
2388: switch (cur->type) {
2389: case XML_LOCAL_NAMESPACE:
2390: ret = xmlNewNs(NULL, cur->href, cur->prefix);
2391: break;
2392: default:
1.86 daniel 2393: #ifdef DEBUG_TREE
1.134 veillard 2394: xmlGenericError(xmlGenericErrorContext,
1.136 veillard 2395: "xmlCopyNamespace: invalid type %d\n", cur->type);
1.86 daniel 2396: #endif
1.31 daniel 2397: return(NULL);
2398: }
2399: return(ret);
2400: }
2401:
2402: /**
2403: * xmlCopyNamespaceList:
2404: * @cur: the first namespace
2405: *
2406: * Do a copy of an namespace list.
2407: *
2408: * Returns: a new xmlNsPtr, or NULL in case of error.
2409: */
2410: xmlNsPtr
2411: xmlCopyNamespaceList(xmlNsPtr cur) {
2412: xmlNsPtr ret = NULL;
2413: xmlNsPtr p = NULL,q;
2414:
2415: while (cur != NULL) {
2416: q = xmlCopyNamespace(cur);
2417: if (p == NULL) {
2418: ret = p = q;
2419: } else {
2420: p->next = q;
2421: p = q;
2422: }
2423: cur = cur->next;
2424: }
2425: return(ret);
2426: }
2427:
2428: /**
2429: * xmlCopyProp:
1.56 daniel 2430: * @target: the element where the attribute will be grafted
1.31 daniel 2431: * @cur: the attribute
2432: *
2433: * Do a copy of the attribute.
2434: *
2435: * Returns: a new xmlAttrPtr, or NULL in case of error.
2436: */
2437: xmlAttrPtr
1.56 daniel 2438: xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
1.31 daniel 2439: xmlAttrPtr ret;
2440:
2441: if (cur == NULL) return(NULL);
1.94 daniel 2442: if (cur->parent != NULL)
2443: ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2444: else if (cur->children != NULL)
1.90 daniel 2445: ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
1.31 daniel 2446: else
2447: ret = xmlNewDocProp(NULL, cur->name, NULL);
2448: if (ret == NULL) return(NULL);
1.94 daniel 2449: ret->parent = target;
1.56 daniel 2450:
2451: if ((cur->ns != NULL) && (target != NULL)) {
2452: xmlNsPtr ns;
2453:
2454: ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2455: ret->ns = ns;
2456: } else
2457: ret->ns = NULL;
2458:
1.140 veillard 2459: if (cur->children != NULL) {
2460: xmlNodePtr tmp;
2461:
1.90 daniel 2462: ret->children = xmlCopyNodeList(cur->children);
1.140 veillard 2463: ret->last = NULL;
2464: tmp = ret->children;
2465: while (tmp != NULL) {
2466: tmp->parent = (xmlNodePtr)ret;
2467: if (tmp->next == NULL)
2468: ret->last = tmp;
2469: tmp = tmp->next;
2470: }
2471: }
1.31 daniel 2472: return(ret);
2473: }
2474:
2475: /**
2476: * xmlCopyPropList:
1.56 daniel 2477: * @target: the element where the attributes will be grafted
1.31 daniel 2478: * @cur: the first attribute
2479: *
2480: * Do a copy of an attribute list.
2481: *
2482: * Returns: a new xmlAttrPtr, or NULL in case of error.
2483: */
2484: xmlAttrPtr
1.56 daniel 2485: xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
1.31 daniel 2486: xmlAttrPtr ret = NULL;
2487: xmlAttrPtr p = NULL,q;
2488:
2489: while (cur != NULL) {
1.56 daniel 2490: q = xmlCopyProp(target, cur);
1.31 daniel 2491: if (p == NULL) {
2492: ret = p = q;
2493: } else {
2494: p->next = q;
1.94 daniel 2495: q->prev = p;
1.31 daniel 2496: p = q;
2497: }
2498: cur = cur->next;
2499: }
2500: return(ret);
2501: }
2502:
2503: /*
1.68 daniel 2504: * NOTE abeut the CopyNode operations !
1.31 daniel 2505: *
2506: * They are splitted into external and internal parts for one
2507: * tricky reason: namespaces. Doing a direct copy of a node
2508: * say RPM:Copyright without changing the namespace pointer to
2509: * something else can produce stale links. One way to do it is
2510: * to keep a reference counter but this doesn't work as soon
2511: * as one move the element or the subtree out of the scope of
2512: * the existing namespace. The actual solution seems to add
2513: * a copy of the namespace at the top of the copied tree if
2514: * not available in the subtree.
2515: * Hence two functions, the public front-end call the inner ones
2516: */
2517:
2518: static xmlNodePtr
2519: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2520:
2521: static xmlNodePtr
2522: xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2523: int recursive) {
2524: xmlNodePtr ret;
2525:
2526: if (node == NULL) return(NULL);
2527: /*
2528: * Allocate a new node and fill the fields.
2529: */
1.57 daniel 2530: ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1.31 daniel 2531: if (ret == NULL) {
1.134 veillard 2532: xmlGenericError(xmlGenericErrorContext,
2533: "xmlStaticCopyNode : malloc failed\n");
1.31 daniel 2534: return(NULL);
2535: }
1.90 daniel 2536: memset(ret, 0, sizeof(xmlNode));
2537: ret->type = node->type;
1.31 daniel 2538:
2539: ret->doc = doc;
2540: ret->parent = parent;
2541: if (node->name != NULL)
2542: ret->name = xmlStrdup(node->name);
1.70 daniel 2543: if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2544: #ifndef XML_USE_BUFFER_CONTENT
1.31 daniel 2545: ret->content = xmlStrdup(node->content);
1.70 daniel 2546: #else
2547: ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2548: xmlBufferSetAllocationScheme(ret->content,
2549: xmlGetBufferAllocationScheme());
2550: xmlBufferAdd(ret->content,
2551: xmlBufferContent(node->content),
2552: xmlBufferLength(node->content));
2553: #endif
1.90 daniel 2554: }
1.31 daniel 2555: if (parent != NULL)
2556: xmlAddChild(parent, ret);
2557:
2558: if (!recursive) return(ret);
2559: if (node->nsDef != NULL)
2560: ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2561:
2562: if (node->ns != NULL) {
2563: xmlNsPtr ns;
2564:
2565: ns = xmlSearchNs(doc, ret, node->ns->prefix);
2566: if (ns == NULL) {
2567: /*
2568: * Humm, we are copying an element whose namespace is defined
2569: * out of the new tree scope. Search it in the original tree
2570: * and add it at the top of the new tree
2571: */
2572: ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2573: if (ns != NULL) {
2574: xmlNodePtr root = ret;
2575:
2576: while (root->parent != NULL) root = root->parent;
2577: xmlNewNs(root, ns->href, ns->prefix);
2578: }
2579: } else {
2580: /*
2581: * reference the existing namespace definition in our own tree.
2582: */
2583: ret->ns = ns;
2584: }
2585: }
1.56 daniel 2586: if (node->properties != NULL)
2587: ret->properties = xmlCopyPropList(ret, node->properties);
1.90 daniel 2588: if (node->children != NULL)
2589: ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
1.140 veillard 2590: UPDATE_LAST_CHILD_AND_PARENT(ret)
1.31 daniel 2591: return(ret);
2592: }
2593:
2594: static xmlNodePtr
2595: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2596: xmlNodePtr ret = NULL;
2597: xmlNodePtr p = NULL,q;
2598:
2599: while (node != NULL) {
2600: q = xmlStaticCopyNode(node, doc, parent, 1);
1.103 daniel 2601: if (ret == NULL) {
2602: q->prev = NULL;
2603: ret = p = q;
1.31 daniel 2604: } else {
1.103 daniel 2605: p->next = q;
2606: q->prev = p;
2607: p = q;
1.31 daniel 2608: }
2609: node = node->next;
2610: }
2611: return(ret);
2612: }
2613:
2614: /**
2615: * xmlCopyNode:
2616: * @node: the node
2617: * @recursive: if 1 do a recursive copy.
2618: *
2619: * Do a copy of the node.
2620: *
2621: * Returns: a new xmlNodePtr, or NULL in case of error.
2622: */
2623: xmlNodePtr
2624: xmlCopyNode(xmlNodePtr node, int recursive) {
2625: xmlNodePtr ret;
2626:
2627: ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2628: return(ret);
2629: }
2630:
2631: /**
2632: * xmlCopyNodeList:
2633: * @node: the first node in the list.
2634: *
2635: * Do a recursive copy of the node list.
2636: *
2637: * Returns: a new xmlNodePtr, or NULL in case of error.
2638: */
2639: xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2640: xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2641: return(ret);
2642: }
2643:
2644: /**
2645: * xmlCopyElement:
2646: * @elem: the element
2647: *
2648: * Do a copy of the element definition.
2649: *
2650: * Returns: a new xmlElementPtr, or NULL in case of error.
2651: xmlElementPtr
2652: xmlCopyElement(xmlElementPtr elem) {
2653: xmlElementPtr ret;
2654:
2655: if (elem == NULL) return(NULL);
2656: ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2657: if (ret == NULL) return(NULL);
2658: if (!recursive) return(ret);
2659: if (elem->properties != NULL)
2660: ret->properties = xmlCopyPropList(elem->properties);
2661:
2662: if (elem->nsDef != NULL)
2663: ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1.90 daniel 2664: if (elem->children != NULL)
2665: ret->children = xmlCopyElementList(elem->children);
1.31 daniel 2666: return(ret);
2667: }
2668: */
2669:
2670: /**
2671: * xmlCopyDtd:
2672: * @dtd: the dtd
2673: *
2674: * Do a copy of the dtd.
2675: *
2676: * Returns: a new xmlDtdPtr, or NULL in case of error.
2677: */
2678: xmlDtdPtr
2679: xmlCopyDtd(xmlDtdPtr dtd) {
2680: xmlDtdPtr ret;
2681:
2682: if (dtd == NULL) return(NULL);
2683: ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2684: if (ret == NULL) return(NULL);
2685: if (dtd->entities != NULL)
2686: ret->entities = (void *) xmlCopyEntitiesTable(
2687: (xmlEntitiesTablePtr) dtd->entities);
1.35 daniel 2688: if (dtd->notations != NULL)
2689: ret->notations = (void *) xmlCopyNotationTable(
2690: (xmlNotationTablePtr) dtd->notations);
2691: if (dtd->elements != NULL)
2692: ret->elements = (void *) xmlCopyElementTable(
2693: (xmlElementTablePtr) dtd->elements);
2694: if (dtd->attributes != NULL)
2695: ret->attributes = (void *) xmlCopyAttributeTable(
2696: (xmlAttributeTablePtr) dtd->attributes);
1.31 daniel 2697: return(ret);
2698: }
2699:
2700: /**
2701: * xmlCopyDoc:
2702: * @doc: the document
2703: * @recursive: if 1 do a recursive copy.
2704: *
2705: * Do a copy of the document info. If recursive, the content tree will
2706: * be copied too as well as Dtd, namespaces and entities.
2707: *
2708: * Returns: a new xmlDocPtr, or NULL in case of error.
2709: */
2710: xmlDocPtr
2711: xmlCopyDoc(xmlDocPtr doc, int recursive) {
2712: xmlDocPtr ret;
2713:
2714: if (doc == NULL) return(NULL);
2715: ret = xmlNewDoc(doc->version);
2716: if (ret == NULL) return(NULL);
2717: if (doc->name != NULL)
1.57 daniel 2718: ret->name = xmlMemStrdup(doc->name);
1.31 daniel 2719: if (doc->encoding != NULL)
2720: ret->encoding = xmlStrdup(doc->encoding);
2721: ret->compression = doc->compression;
2722: ret->standalone = doc->standalone;
2723: if (!recursive) return(ret);
2724:
2725: if (doc->intSubset != NULL)
2726: ret->intSubset = xmlCopyDtd(doc->intSubset);
2727: if (doc->oldNs != NULL)
2728: ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1.140 veillard 2729: if (doc->children != NULL) {
2730: xmlNodePtr tmp;
1.103 daniel 2731: ret->children = xmlStaticCopyNodeList(doc->children, ret,
2732: (xmlNodePtr)ret);
1.140 veillard 2733: ret->last = NULL;
2734: tmp = ret->children;
2735: while (tmp != NULL) {
2736: if (tmp->next == NULL)
2737: ret->last = tmp;
2738: tmp = tmp->next;
2739: }
2740: }
1.31 daniel 2741: return(ret);
2742: }
2743:
2744: /************************************************************************
2745: * *
1.1 veillard 2746: * Content access functions *
2747: * *
2748: ************************************************************************/
2749:
1.23 daniel 2750: /**
1.75 daniel 2751: * xmlDocGetRootElement:
2752: * @doc: the document
2753: *
1.90 daniel 2754: * Get the root element of the document (doc->children is a list
1.75 daniel 2755: * containing possibly comments, PIs, etc ...).
2756: *
2757: * Returns the xmlNodePtr for the root or NULL
2758: */
2759: xmlNodePtr
2760: xmlDocGetRootElement(xmlDocPtr doc) {
2761: xmlNodePtr ret;
2762:
2763: if (doc == NULL) return(NULL);
1.90 daniel 2764: ret = doc->children;
1.75 daniel 2765: while (ret != NULL) {
2766: if (ret->type == XML_ELEMENT_NODE)
2767: return(ret);
2768: ret = ret->next;
2769: }
2770: return(ret);
2771: }
2772:
2773: /**
1.78 daniel 2774: * xmlDocSetRootElement:
2775: * @doc: the document
2776: * @root: the new document root element
2777: *
1.90 daniel 2778: * Set the root element of the document (doc->children is a list
1.78 daniel 2779: * containing possibly comments, PIs, etc ...).
2780: *
2781: * Returns the old root element if any was found
2782: */
2783: xmlNodePtr
2784: xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2785: xmlNodePtr old = NULL;
2786:
2787: if (doc == NULL) return(NULL);
1.90 daniel 2788: old = doc->children;
1.78 daniel 2789: while (old != NULL) {
2790: if (old->type == XML_ELEMENT_NODE)
2791: break;
2792: old = old->next;
2793: }
2794: if (old == NULL) {
1.90 daniel 2795: if (doc->children == NULL) {
2796: doc->children = root;
1.140 veillard 2797: doc->last = root;
1.78 daniel 2798: } else {
1.90 daniel 2799: xmlAddSibling(doc->children, root);
1.78 daniel 2800: }
2801: } else {
2802: xmlReplaceNode(old, root);
2803: }
2804: return(old);
2805: }
2806:
2807: /**
1.52 daniel 2808: * xmlNodeSetLang:
2809: * @cur: the node being changed
2810: * @lang: the langage description
2811: *
1.78 daniel 2812: * Set the language of a node, i.e. the values of the xml:lang
2813: * attribute.
1.52 daniel 2814: */
2815: void
1.61 daniel 2816: xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
1.78 daniel 2817: if (cur == NULL) return;
2818: switch(cur->type) {
2819: case XML_TEXT_NODE:
2820: case XML_CDATA_SECTION_NODE:
2821: case XML_COMMENT_NODE:
2822: case XML_DOCUMENT_NODE:
2823: case XML_DOCUMENT_TYPE_NODE:
2824: case XML_DOCUMENT_FRAG_NODE:
2825: case XML_NOTATION_NODE:
2826: case XML_HTML_DOCUMENT_NODE:
1.90 daniel 2827: case XML_DTD_NODE:
1.91 daniel 2828: case XML_ELEMENT_DECL:
2829: case XML_ATTRIBUTE_DECL:
1.96 daniel 2830: case XML_ENTITY_DECL:
1.121 veillard 2831: case XML_PI_NODE:
2832: case XML_ENTITY_REF_NODE:
2833: case XML_ENTITY_NODE:
1.136 veillard 2834: case XML_NAMESPACE_DECL:
1.123 veillard 2835: #ifdef LIBXML_SGML_ENABLED
2836: case XML_SGML_DOCUMENT_NODE:
2837: #endif
1.138 veillard 2838: case XML_XINCLUDE_START:
2839: case XML_XINCLUDE_END:
1.78 daniel 2840: return;
2841: case XML_ELEMENT_NODE:
2842: case XML_ATTRIBUTE_NODE:
2843: break;
2844: }
1.54 daniel 2845: xmlSetProp(cur, BAD_CAST "xml:lang", lang);
1.52 daniel 2846: }
2847:
2848: /**
2849: * xmlNodeGetLang:
2850: * @cur: the node being checked
2851: *
2852: * Searches the language of a node, i.e. the values of the xml:lang
2853: * attribute or the one carried by the nearest ancestor.
2854: *
2855: * Returns a pointer to the lang value, or NULL if not found
1.69 daniel 2856: * It's up to the caller to free the memory.
1.52 daniel 2857: */
1.69 daniel 2858: xmlChar *
1.52 daniel 2859: xmlNodeGetLang(xmlNodePtr cur) {
1.69 daniel 2860: xmlChar *lang;
1.52 daniel 2861:
2862: while (cur != NULL) {
1.54 daniel 2863: lang = xmlGetProp(cur, BAD_CAST "xml:lang");
1.52 daniel 2864: if (lang != NULL)
2865: return(lang);
2866: cur = cur->parent;
2867: }
2868: return(NULL);
1.78 daniel 2869: }
2870:
1.133 veillard 2871:
2872: /**
2873: * xmlNodeSetSpacePreserve:
2874: * @cur: the node being changed
2875: * @val: the xml:space value ("0": default, 1: "preserve")
2876: *
2877: * Set (or reset) the space preserving behaviour of a node, i.e. the
2878: * value of the xml:space attribute.
2879: */
2880: void
2881: xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2882: if (cur == NULL) return;
2883: switch(cur->type) {
2884: case XML_TEXT_NODE:
2885: case XML_CDATA_SECTION_NODE:
2886: case XML_COMMENT_NODE:
2887: case XML_DOCUMENT_NODE:
2888: case XML_DOCUMENT_TYPE_NODE:
2889: case XML_DOCUMENT_FRAG_NODE:
2890: case XML_NOTATION_NODE:
2891: case XML_HTML_DOCUMENT_NODE:
2892: case XML_DTD_NODE:
2893: case XML_ELEMENT_DECL:
2894: case XML_ATTRIBUTE_DECL:
2895: case XML_ENTITY_DECL:
2896: case XML_PI_NODE:
2897: case XML_ENTITY_REF_NODE:
2898: case XML_ENTITY_NODE:
1.136 veillard 2899: case XML_NAMESPACE_DECL:
1.138 veillard 2900: case XML_XINCLUDE_START:
2901: case XML_XINCLUDE_END:
1.133 veillard 2902: #ifdef LIBXML_SGML_ENABLED
2903: case XML_SGML_DOCUMENT_NODE:
2904: #endif
2905: return;
2906: case XML_ELEMENT_NODE:
2907: case XML_ATTRIBUTE_NODE:
2908: break;
2909: }
2910: switch (val) {
2911: case 0:
2912: xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2913: break;
2914: case 1:
2915: xmlSetProp(cur, BAD_CAST "xml:space",
2916: BAD_CAST "preserve");
2917: break;
2918: }
2919: }
2920:
1.78 daniel 2921: /**
1.98 daniel 2922: * xmlNodeGetSpacePreserve:
2923: * @cur: the node being checked
2924: *
1.133 veillard 2925: * Searches the space preserving behaviour of a node, i.e. the values
2926: * of the xml:space attribute or the one carried by the nearest
2927: * ancestor.
1.98 daniel 2928: *
2929: * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2930: */
2931: int
2932: xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2933: xmlChar *space;
2934:
2935: while (cur != NULL) {
2936: space = xmlGetProp(cur, BAD_CAST "xml:space");
2937: if (space != NULL) {
1.128 veillard 2938: if (xmlStrEqual(space, BAD_CAST "preserve")) {
1.98 daniel 2939: xmlFree(space);
2940: return(1);
2941: }
1.128 veillard 2942: if (xmlStrEqual(space, BAD_CAST "default")) {
1.98 daniel 2943: xmlFree(space);
2944: return(0);
2945: }
2946: xmlFree(space);
2947: }
2948: cur = cur->parent;
2949: }
2950: return(-1);
2951: }
2952:
2953: /**
1.78 daniel 2954: * xmlNodeSetName:
2955: * @cur: the node being changed
2956: * @name: the new tag name
2957: *
1.133 veillard 2958: * Set (or reset) the name of a node.
1.78 daniel 2959: */
2960: void
2961: xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2962: if (cur == NULL) return;
2963: if (name == NULL) return;
2964: switch(cur->type) {
2965: case XML_TEXT_NODE:
2966: case XML_CDATA_SECTION_NODE:
2967: case XML_COMMENT_NODE:
2968: case XML_DOCUMENT_TYPE_NODE:
2969: case XML_DOCUMENT_FRAG_NODE:
2970: case XML_NOTATION_NODE:
2971: case XML_HTML_DOCUMENT_NODE:
1.136 veillard 2972: case XML_NAMESPACE_DECL:
1.138 veillard 2973: case XML_XINCLUDE_START:
2974: case XML_XINCLUDE_END:
1.123 veillard 2975: #ifdef LIBXML_SGML_ENABLED
2976: case XML_SGML_DOCUMENT_NODE:
2977: #endif
1.78 daniel 2978: return;
2979: case XML_ELEMENT_NODE:
2980: case XML_ATTRIBUTE_NODE:
2981: case XML_PI_NODE:
2982: case XML_ENTITY_REF_NODE:
2983: case XML_ENTITY_NODE:
1.90 daniel 2984: case XML_DTD_NODE:
2985: case XML_DOCUMENT_NODE:
1.96 daniel 2986: case XML_ELEMENT_DECL:
2987: case XML_ATTRIBUTE_DECL:
2988: case XML_ENTITY_DECL:
1.78 daniel 2989: break;
2990: }
2991: if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
2992: cur->name = xmlStrdup(name);
1.52 daniel 2993: }
2994:
1.133 veillard 2995: /**
2996: * xmlNodeSetBase:
2997: * @cur: the node being changed
2998: * @uri: the new base URI
2999: *
3000: * Set (or reset) the base URI of a node, i.e. the value of the
3001: * xml:base attribute.
3002: */
3003: void
3004: xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3005: if (cur == NULL) return;
3006: switch(cur->type) {
3007: case XML_TEXT_NODE:
3008: case XML_CDATA_SECTION_NODE:
3009: case XML_COMMENT_NODE:
3010: case XML_DOCUMENT_NODE:
3011: case XML_DOCUMENT_TYPE_NODE:
3012: case XML_DOCUMENT_FRAG_NODE:
3013: case XML_NOTATION_NODE:
3014: case XML_HTML_DOCUMENT_NODE:
3015: case XML_DTD_NODE:
3016: case XML_ELEMENT_DECL:
3017: case XML_ATTRIBUTE_DECL:
3018: case XML_ENTITY_DECL:
3019: case XML_PI_NODE:
3020: case XML_ENTITY_REF_NODE:
3021: case XML_ENTITY_NODE:
1.136 veillard 3022: case XML_NAMESPACE_DECL:
1.138 veillard 3023: case XML_XINCLUDE_START:
3024: case XML_XINCLUDE_END:
1.133 veillard 3025: #ifdef LIBXML_SGML_ENABLED
3026: case XML_SGML_DOCUMENT_NODE:
3027: #endif
3028: return;
3029: case XML_ELEMENT_NODE:
3030: case XML_ATTRIBUTE_NODE:
3031: break;
3032: }
3033: xmlSetProp(cur, BAD_CAST "xml:base", uri);
3034: }
3035:
1.52 daniel 3036: /**
1.139 veillard 3037: * xmlDocumentGetBase:
3038: * @doc: the document
3039: *
3040: * Searches for the Document BASE URL. The code should work on both XML
3041: * and HTML document.
3042: * It returns the base as defined in RFC 2396 section
3043: * 5.1.3. Base URI from the Retrieval URI
3044: * However it does not return the computed base (5.1.1 and 5.1.2), use
3045: * xmlNodeGetBase() for this
3046: *
3047: * Returns a pointer to the base URL, or NULL if not found
3048: * It's up to the caller to free the memory.
3049: */
3050: xmlChar *
3051: xmlDocumentGetBase(xmlDocPtr doc) {
3052: if (doc == NULL)
3053: return(NULL);
3054: if (doc->type == XML_HTML_DOCUMENT_NODE) {
3055: if (doc->URL != NULL)
3056: return(xmlStrdup(doc->URL));
3057: return(NULL);
3058: }
3059: if (doc->URL != NULL)
3060: return(xmlStrdup(doc->URL));
3061: return(NULL);
3062: }
3063:
3064: /**
1.73 daniel 3065: * xmlNodeGetBase:
3066: * @doc: the document the node pertains to
3067: * @cur: the node being checked
3068: *
3069: * Searches for the BASE URL. The code should work on both XML
3070: * and HTML document even if base mechanisms are completely different.
1.139 veillard 3071: * It returns the base as defined in RFC 2396 sections
3072: * 5.1.1. Base URI within Document Content
3073: * and
3074: * 5.1.2. Base URI from the Encapsulating Entity
3075: * However it does not return the document base (5.1.3), use
3076: * xmlDocumentGetBase() for this
1.73 daniel 3077: *
3078: * Returns a pointer to the base URL, or NULL if not found
3079: * It's up to the caller to free the memory.
3080: */
3081: xmlChar *
3082: xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3083: xmlChar *base;
3084:
3085: if ((cur == NULL) && (doc == NULL))
3086: return(NULL);
3087: if (doc == NULL) doc = cur->doc;
3088: if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
1.90 daniel 3089: cur = doc->children;
1.73 daniel 3090: while ((cur != NULL) && (cur->name != NULL)) {
3091: if (cur->type != XML_ELEMENT_NODE) {
3092: cur = cur->next;
3093: continue;
3094: }
1.126 veillard 3095: if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
1.90 daniel 3096: cur = cur->children;
1.73 daniel 3097: continue;
3098: }
1.126 veillard 3099: if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
1.90 daniel 3100: cur = cur->children;
1.73 daniel 3101: continue;
3102: }
1.126 veillard 3103: if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3104: return(xmlGetProp(cur, BAD_CAST "href"));
1.73 daniel 3105: }
1.100 daniel 3106: cur = cur->next;
1.73 daniel 3107: }
3108: return(NULL);
3109: }
3110: while (cur != NULL) {
1.139 veillard 3111: if (cur->type == XML_ENTITY_DECL) {
3112: xmlEntityPtr ent = (xmlEntityPtr) cur;
3113: return(xmlStrdup(ent->URI));
3114: }
1.73 daniel 3115: base = xmlGetProp(cur, BAD_CAST "xml:base");
3116: if (base != NULL)
3117: return(base);
3118: cur = cur->parent;
3119: }
3120: return(NULL);
3121: }
3122:
3123: /**
1.28 daniel 3124: * xmlNodeGetContent:
3125: * @cur: the node being read
3126: *
3127: * Read the value of a node, this can be either the text carried
3128: * directly by this node if it's a TEXT node or the aggregate string
3129: * of the values carried by this node child's (TEXT and ENTITY_REF).
3130: * Entity references are substitued.
1.61 daniel 3131: * Returns a new xmlChar * or NULL if no content is available.
1.38 daniel 3132: * It's up to the caller to free the memory.
1.28 daniel 3133: */
1.61 daniel 3134: xmlChar *
1.28 daniel 3135: xmlNodeGetContent(xmlNodePtr cur) {
3136: if (cur == NULL) return(NULL);
3137: switch (cur->type) {
3138: case XML_DOCUMENT_FRAG_NODE:
3139: case XML_ELEMENT_NODE:
1.90 daniel 3140: return(xmlNodeListGetString(cur->doc, cur->children, 1));
1.28 daniel 3141: break;
1.52 daniel 3142: case XML_ATTRIBUTE_NODE: {
3143: xmlAttrPtr attr = (xmlAttrPtr) cur;
1.90 daniel 3144: if (attr->parent != NULL)
3145: return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
1.52 daniel 3146: else
1.90 daniel 3147: return(xmlNodeListGetString(NULL, attr->children, 1));
1.52 daniel 3148: break;
3149: }
1.82 daniel 3150: case XML_COMMENT_NODE:
1.52 daniel 3151: case XML_PI_NODE:
3152: if (cur->content != NULL)
1.70 daniel 3153: #ifndef XML_USE_BUFFER_CONTENT
1.52 daniel 3154: return(xmlStrdup(cur->content));
1.70 daniel 3155: #else
3156: return(xmlStrdup(xmlBufferContent(cur->content)));
3157: #endif
1.52 daniel 3158: return(NULL);
1.28 daniel 3159: case XML_ENTITY_REF_NODE:
1.82 daniel 3160: /*
3161: * Locate the entity, and get it's content
3162: * @@@
3163: */
3164: return(NULL);
1.28 daniel 3165: case XML_ENTITY_NODE:
3166: case XML_DOCUMENT_NODE:
1.65 daniel 3167: case XML_HTML_DOCUMENT_NODE:
1.28 daniel 3168: case XML_DOCUMENT_TYPE_NODE:
3169: case XML_NOTATION_NODE:
1.90 daniel 3170: case XML_DTD_NODE:
1.138 veillard 3171: case XML_XINCLUDE_START:
3172: case XML_XINCLUDE_END:
1.123 veillard 3173: #ifdef LIBXML_SGML_ENABLED
3174: case XML_SGML_DOCUMENT_NODE:
3175: #endif
1.28 daniel 3176: return(NULL);
1.136 veillard 3177: case XML_NAMESPACE_DECL:
1.142 veillard 3178: return(xmlStrdup(((xmlNsPtr)cur)->href));
1.91 daniel 3179: case XML_ELEMENT_DECL:
3180: /* TODO !!! */
3181: return(NULL);
3182: case XML_ATTRIBUTE_DECL:
3183: /* TODO !!! */
3184: return(NULL);
1.96 daniel 3185: case XML_ENTITY_DECL:
3186: /* TODO !!! */
3187: return(NULL);
1.50 daniel 3188: case XML_CDATA_SECTION_NODE:
1.28 daniel 3189: case XML_TEXT_NODE:
3190: if (cur->content != NULL)
1.70 daniel 3191: #ifndef XML_USE_BUFFER_CONTENT
1.28 daniel 3192: return(xmlStrdup(cur->content));
1.70 daniel 3193: #else
3194: return(xmlStrdup(xmlBufferContent(cur->content)));
3195: #endif
1.28 daniel 3196: return(NULL);
3197: }
3198: return(NULL);
3199: }
3200:
3201: /**
1.23 daniel 3202: * xmlNodeSetContent:
3203: * @cur: the node being modified
3204: * @content: the new value of the content
3205: *
3206: * Replace the content of a node.
1.1 veillard 3207: */
1.28 daniel 3208: void
1.61 daniel 3209: xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
1.1 veillard 3210: if (cur == NULL) {
1.86 daniel 3211: #ifdef DEBUG_TREE
1.134 veillard 3212: xmlGenericError(xmlGenericErrorContext,
3213: "xmlNodeSetContent : node == NULL\n");
1.86 daniel 3214: #endif
1.1 veillard 3215: return;
3216: }
1.28 daniel 3217: switch (cur->type) {
3218: case XML_DOCUMENT_FRAG_NODE:
3219: case XML_ELEMENT_NODE:
3220: if (cur->content != NULL) {
1.70 daniel 3221: #ifndef XML_USE_BUFFER_CONTENT
1.57 daniel 3222: xmlFree(cur->content);
1.70 daniel 3223: #else
3224: xmlBufferFree(cur->content);
3225: #endif
1.28 daniel 3226: cur->content = NULL;
3227: }
1.90 daniel 3228: if (cur->children != NULL) xmlFreeNodeList(cur->children);
3229: cur->children = xmlStringGetNodeList(cur->doc, content);
1.140 veillard 3230: UPDATE_LAST_CHILD_AND_PARENT(cur)
1.28 daniel 3231: break;
3232: case XML_ATTRIBUTE_NODE:
3233: break;
3234: case XML_TEXT_NODE:
3235: case XML_CDATA_SECTION_NODE:
3236: case XML_ENTITY_REF_NODE:
3237: case XML_ENTITY_NODE:
3238: case XML_PI_NODE:
3239: case XML_COMMENT_NODE:
1.70 daniel 3240: if (cur->content != NULL) {
3241: #ifndef XML_USE_BUFFER_CONTENT
3242: xmlFree(cur->content);
3243: #else
3244: xmlBufferFree(cur->content);
3245: #endif
3246: }
1.90 daniel 3247: if (cur->children != NULL) xmlFreeNodeList(cur->children);
3248: cur->last = cur->children = NULL;
1.70 daniel 3249: if (content != NULL) {
3250: #ifndef XML_USE_BUFFER_CONTENT
1.28 daniel 3251: cur->content = xmlStrdup(content);
1.70 daniel 3252: #else
3253: cur->content = xmlBufferCreateSize(0);
3254: xmlBufferSetAllocationScheme(cur->content,
3255: xmlGetBufferAllocationScheme());
3256: xmlBufferAdd(cur->content, content, -1);
3257: #endif
3258: } else
1.28 daniel 3259: cur->content = NULL;
1.53 daniel 3260: break;
1.28 daniel 3261: case XML_DOCUMENT_NODE:
1.65 daniel 3262: case XML_HTML_DOCUMENT_NODE:
1.28 daniel 3263: case XML_DOCUMENT_TYPE_NODE:
1.138 veillard 3264: case XML_XINCLUDE_START:
3265: case XML_XINCLUDE_END:
1.123 veillard 3266: #ifdef LIBXML_SGML_ENABLED
3267: case XML_SGML_DOCUMENT_NODE:
3268: #endif
1.28 daniel 3269: break;
3270: case XML_NOTATION_NODE:
3271: break;
1.90 daniel 3272: case XML_DTD_NODE:
3273: break;
1.136 veillard 3274: case XML_NAMESPACE_DECL:
3275: break;
1.91 daniel 3276: case XML_ELEMENT_DECL:
3277: /* TODO !!! */
3278: break;
3279: case XML_ATTRIBUTE_DECL:
3280: /* TODO !!! */
3281: break;
1.96 daniel 3282: case XML_ENTITY_DECL:
3283: /* TODO !!! */
3284: break;
1.28 daniel 3285: }
1.1 veillard 3286: }
3287:
1.23 daniel 3288: /**
3289: * xmlNodeSetContentLen:
3290: * @cur: the node being modified
3291: * @content: the new value of the content
3292: * @len: the size of @content
3293: *
3294: * Replace the content of a node.
1.21 daniel 3295: */
1.28 daniel 3296: void
1.61 daniel 3297: xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
1.21 daniel 3298: if (cur == NULL) {
1.86 daniel 3299: #ifdef DEBUG_TREE
1.134 veillard 3300: xmlGenericError(xmlGenericErrorContext,
3301: "xmlNodeSetContentLen : node == NULL\n");
1.86 daniel 3302: #endif
1.21 daniel 3303: return;
3304: }
1.28 daniel 3305: switch (cur->type) {
3306: case XML_DOCUMENT_FRAG_NODE:
3307: case XML_ELEMENT_NODE:
3308: if (cur->content != NULL) {
1.70 daniel 3309: #ifndef XML_USE_BUFFER_CONTENT
1.57 daniel 3310: xmlFree(cur->content);
1.70 daniel 3311: #else
3312: xmlBufferFree(cur->content);
3313: #endif
1.28 daniel 3314: cur->content = NULL;
3315: }
1.90 daniel 3316: if (cur->children != NULL) xmlFreeNodeList(cur->children);
3317: cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
1.140 veillard 3318: UPDATE_LAST_CHILD_AND_PARENT(cur)
1.28 daniel 3319: break;
3320: case XML_ATTRIBUTE_NODE:
3321: break;
3322: case XML_TEXT_NODE:
3323: case XML_CDATA_SECTION_NODE:
3324: case XML_ENTITY_REF_NODE:
3325: case XML_ENTITY_NODE:
3326: case XML_PI_NODE:
3327: case XML_COMMENT_NODE:
1.70 daniel 3328: case XML_NOTATION_NODE:
3329: if (cur->content != NULL) {
3330: #ifndef XML_USE_BUFFER_CONTENT
3331: xmlFree(cur->content);
3332: #else
3333: xmlBufferFree(cur->content);
3334: #endif
3335: }
1.90 daniel 3336: if (cur->children != NULL) xmlFreeNodeList(cur->children);
3337: cur->children = cur->last = NULL;
1.70 daniel 3338: if (content != NULL) {
3339: #ifndef XML_USE_BUFFER_CONTENT
1.28 daniel 3340: cur->content = xmlStrndup(content, len);
1.70 daniel 3341: #else
3342: cur->content = xmlBufferCreateSize(len);
3343: xmlBufferSetAllocationScheme(cur->content,
3344: xmlGetBufferAllocationScheme());
3345: xmlBufferAdd(cur->content, content, len);
3346: #endif
3347: } else
1.28 daniel 3348: cur->content = NULL;
1.53 daniel 3349: break;
1.28 daniel 3350: case XML_DOCUMENT_NODE:
1.90 daniel 3351: case XML_DTD_NODE:
1.65 daniel 3352: case XML_HTML_DOCUMENT_NODE:
1.28 daniel 3353: case XML_DOCUMENT_TYPE_NODE:
1.136 veillard 3354: case XML_NAMESPACE_DECL:
1.138 veillard 3355: case XML_XINCLUDE_START:
3356: case XML_XINCLUDE_END:
1.123 veillard 3357: #ifdef LIBXML_SGML_ENABLED
3358: case XML_SGML_DOCUMENT_NODE:
3359: #endif
1.28 daniel 3360: break;
1.91 daniel 3361: case XML_ELEMENT_DECL:
3362: /* TODO !!! */
3363: break;
3364: case XML_ATTRIBUTE_DECL:
3365: /* TODO !!! */
3366: break;
1.96 daniel 3367: case XML_ENTITY_DECL:
3368: /* TODO !!! */
3369: break;
1.28 daniel 3370: }
1.21 daniel 3371: }
3372:
1.23 daniel 3373: /**
1.28 daniel 3374: * xmlNodeAddContentLen:
1.23 daniel 3375: * @cur: the node being modified
3376: * @content: extra content
1.28 daniel 3377: * @len: the size of @content
1.23 daniel 3378: *
3379: * Append the extra substring to the node content.
1.21 daniel 3380: */
1.28 daniel 3381: void
1.61 daniel 3382: xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
1.21 daniel 3383: if (cur == NULL) {
1.86 daniel 3384: #ifdef DEBUG_TREE
1.134 veillard 3385: xmlGenericError(xmlGenericErrorContext,
3386: "xmlNodeAddContentLen : node == NULL\n");
1.86 daniel 3387: #endif
1.21 daniel 3388: return;
3389: }
1.28 daniel 3390: if (len <= 0) return;
3391: switch (cur->type) {
3392: case XML_DOCUMENT_FRAG_NODE:
3393: case XML_ELEMENT_NODE: {
1.112 veillard 3394: xmlNodePtr last = NULL, newNode;
1.28 daniel 3395:
1.90 daniel 3396: if (cur->children != NULL) {
1.32 daniel 3397: last = cur->last;
1.28 daniel 3398: } else {
3399: if (cur->content != NULL) {
1.70 daniel 3400: #ifndef XML_USE_BUFFER_CONTENT
1.90 daniel 3401: cur->children = xmlStringGetNodeList(cur->doc, cur->content);
1.70 daniel 3402: #else
1.90 daniel 3403: cur->children = xmlStringGetNodeList(cur->doc,
1.70 daniel 3404: xmlBufferContent(cur->content));
3405: #endif
1.140 veillard 3406: UPDATE_LAST_CHILD_AND_PARENT(cur)
1.70 daniel 3407: #ifndef XML_USE_BUFFER_CONTENT
1.57 daniel 3408: xmlFree(cur->content);
1.70 daniel 3409: #else
3410: xmlBufferFree(cur->content);
3411: #endif
1.28 daniel 3412: cur->content = NULL;
1.32 daniel 3413: last = cur->last;
1.28 daniel 3414: }
3415: }
1.112 veillard 3416: newNode = xmlNewTextLen(content, len);
3417: if (newNode != NULL) {
3418: xmlAddChild(cur, newNode);
3419: if ((last != NULL) && (last->next == newNode)) {
3420: xmlTextMerge(last, newNode);
1.32 daniel 3421: }
1.28 daniel 3422: }
3423: break;
3424: }
3425: case XML_ATTRIBUTE_NODE:
3426: break;
3427: case XML_TEXT_NODE:
3428: case XML_CDATA_SECTION_NODE:
3429: case XML_ENTITY_REF_NODE:
3430: case XML_ENTITY_NODE:
3431: case XML_PI_NODE:
3432: case XML_COMMENT_NODE:
1.70 daniel 3433: case XML_NOTATION_NODE:
3434: if (content != NULL) {
3435: #ifndef XML_USE_BUFFER_CONTENT
1.28 daniel 3436: cur->content = xmlStrncat(cur->content, content, len);
1.70 daniel 3437: #else
3438: xmlBufferAdd(cur->content, content, len);
3439: #endif
3440: }
1.28 daniel 3441: case XML_DOCUMENT_NODE:
1.90 daniel 3442: case XML_DTD_NODE:
1.65 daniel 3443: case XML_HTML_DOCUMENT_NODE:
1.28 daniel 3444: case XML_DOCUMENT_TYPE_NODE:
1.136 veillard 3445: case XML_NAMESPACE_DECL:
1.138 veillard 3446: case XML_XINCLUDE_START:
3447: case XML_XINCLUDE_END:
1.123 veillard 3448: #ifdef LIBXML_SGML_ENABLED
3449: case XML_SGML_DOCUMENT_NODE:
3450: #endif
1.28 daniel 3451: break;
1.91 daniel 3452: case XML_ELEMENT_DECL:
3453: case XML_ATTRIBUTE_DECL:
1.96 daniel 3454: case XML_ENTITY_DECL:
1.91 daniel 3455: break;
1.28 daniel 3456: }
1.21 daniel 3457: }
3458:
1.23 daniel 3459: /**
1.28 daniel 3460: * xmlNodeAddContent:
1.23 daniel 3461: * @cur: the node being modified
3462: * @content: extra content
3463: *
3464: * Append the extra substring to the node content.
1.21 daniel 3465: */
1.28 daniel 3466: void
1.61 daniel 3467: xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
1.28 daniel 3468: int len;
3469:
1.21 daniel 3470: if (cur == NULL) {
1.86 daniel 3471: #ifdef DEBUG_TREE
1.134 veillard 3472: xmlGenericError(xmlGenericErrorContext,
3473: "xmlNodeAddContent : node == NULL\n");
1.86 daniel 3474: #endif
1.21 daniel 3475: return;
3476: }
1.28 daniel 3477: if (content == NULL) return;
3478: len = xmlStrlen(content);
3479: xmlNodeAddContentLen(cur, content, len);
3480: }
3481:
3482: /**
3483: * xmlTextMerge:
3484: * @first: the first text node
3485: * @second: the second text node being merged
3486: *
3487: * Merge two text nodes into one
1.36 daniel 3488: * Returns the first text node augmented
1.28 daniel 3489: */
3490: xmlNodePtr
3491: xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3492: if (first == NULL) return(second);
3493: if (second == NULL) return(first);
3494: if (first->type != XML_TEXT_NODE) return(first);
3495: if (second->type != XML_TEXT_NODE) return(first);
1.70 daniel 3496: #ifndef XML_USE_BUFFER_CONTENT
1.28 daniel 3497: xmlNodeAddContent(first, second->content);
1.70 daniel 3498: #else
3499: xmlNodeAddContent(first, xmlBufferContent(second->content));
3500: #endif
1.28 daniel 3501: xmlUnlinkNode(second);
3502: xmlFreeNode(second);
3503: return(first);
1.21 daniel 3504: }
3505:
1.23 daniel 3506: /**
1.52 daniel 3507: * xmlGetNsList:
3508: * @doc: the document
3509: * @node: the current node
3510: *
3511: * Search all the namespace applying to a given element.
3512: * Returns an NULL terminated array of all the xmlNsPtr found
3513: * that need to be freed by the caller or NULL if no
3514: * namespace if defined
3515: */
3516: xmlNsPtr *
3517: xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3518: xmlNsPtr cur;
3519: xmlNsPtr *ret = NULL;
3520: int nbns = 0;
3521: int maxns = 10;
3522: int i;
3523:
3524: while (node != NULL) {
3525: cur = node->nsDef;
3526: while (cur != NULL) {
3527: if (ret == NULL) {
1.57 daniel 3528: ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
1.52 daniel 3529: if (ret == NULL) {
1.134 veillard 3530: xmlGenericError(xmlGenericErrorContext,
3531: "xmlGetNsList : out of memory!\n");
1.52 daniel 3532: return(NULL);
3533: }
3534: ret[nbns] = NULL;
3535: }
3536: for (i = 0;i < nbns;i++) {
3537: if ((cur->prefix == ret[i]->prefix) ||
1.128 veillard 3538: (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
1.52 daniel 3539: }
3540: if (i >= nbns) {
3541: if (nbns >= maxns) {
3542: maxns *= 2;
1.57 daniel 3543: ret = (xmlNsPtr *) xmlRealloc(ret,
1.52 daniel 3544: (maxns + 1) * sizeof(xmlNsPtr));
3545: if (ret == NULL) {
1.134 veillard 3546: xmlGenericError(xmlGenericErrorContext,
3547: "xmlGetNsList : realloc failed!\n");
1.52 daniel 3548: return(NULL);
3549: }
3550: }
3551: ret[nbns++] = cur;
3552: ret[nbns] = NULL;
3553: }
3554:
3555: cur = cur->next;
3556: }
3557: node = node->parent;
3558: }
3559: return(ret);
3560: }
3561:
3562: /**
1.23 daniel 3563: * xmlSearchNs:
3564: * @doc: the document
3565: * @node: the current node
3566: * @nameSpace: the namespace string
3567: *
1.16 daniel 3568: * Search a Ns registered under a given name space for a document.
1.23 daniel 3569: * recurse on the parents until it finds the defined namespace
3570: * or return NULL otherwise.
3571: * @nameSpace can be NULL, this is a search for the default namespace.
1.120 veillard 3572: * We don't allow to cross entities boundaries. If you don't declare
3573: * the namespace within those you will be in troubles !!! A warning
3574: * is generated to cover this case.
3575: *
1.36 daniel 3576: * Returns the namespace pointer or NULL.
1.3 veillard 3577: */
1.28 daniel 3578: xmlNsPtr
1.61 daniel 3579: xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
1.16 daniel 3580: xmlNsPtr cur;
1.3 veillard 3581:
1.76 daniel 3582: if (node == NULL) return(NULL);
1.19 daniel 3583: while (node != NULL) {
1.120 veillard 3584: if ((node->type == XML_ENTITY_REF_NODE) ||
3585: (node->type == XML_ENTITY_NODE) ||
3586: (node->type == XML_ENTITY_DECL))
3587: return(NULL);
1.92 daniel 3588: if (node->type == XML_ELEMENT_NODE) {
3589: cur = node->nsDef;
3590: while (cur != NULL) {
1.120 veillard 3591: if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3592: (cur->href != NULL))
1.92 daniel 3593: return(cur);
3594: if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1.120 veillard 3595: (cur->href != NULL) &&
1.128 veillard 3596: (xmlStrEqual(cur->prefix, nameSpace)))
1.92 daniel 3597: return(cur);
3598: cur = cur->next;
3599: }
1.19 daniel 3600: }
3601: node = node->parent;
3602: }
3603: return(NULL);
3604: }
1.3 veillard 3605:
1.23 daniel 3606: /**
3607: * xmlSearchNsByHref:
3608: * @doc: the document
3609: * @node: the current node
3610: * @href: the namespace value
3611: *
3612: * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3613: * the defined namespace or return NULL otherwise.
1.36 daniel 3614: * Returns the namespace pointer or NULL.
1.19 daniel 3615: */
1.28 daniel 3616: xmlNsPtr
1.61 daniel 3617: xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
1.19 daniel 3618: xmlNsPtr cur;
1.82 daniel 3619: xmlNodePtr orig = node;
1.19 daniel 3620:
1.74 daniel 3621: if ((node == NULL) || (href == NULL)) return(NULL);
1.19 daniel 3622: while (node != NULL) {
3623: cur = node->nsDef;
3624: while (cur != NULL) {
3625: if ((cur->href != NULL) && (href != NULL) &&
1.128 veillard 3626: (xmlStrEqual(cur->href, href))) {
1.82 daniel 3627: /*
3628: * Check that the prefix is not shadowed between orig and node
3629: */
3630: xmlNodePtr check = orig;
3631: xmlNsPtr tst;
3632:
3633: while (check != node) {
3634: tst = check->nsDef;
3635: while (tst != NULL) {
3636: if ((tst->prefix == NULL) && (cur->prefix == NULL))
3637: goto shadowed;
3638: if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
1.128 veillard 3639: (xmlStrEqual(tst->prefix, cur->prefix)))
1.82 daniel 3640: goto shadowed;
3641: tst = tst->next;
3642: }
1.135 veillard 3643: check = check->parent;
1.82 daniel 3644: }
1.19 daniel 3645: return(cur);
1.82 daniel 3646: }
3647: shadowed:
1.19 daniel 3648: cur = cur->next;
3649: }
3650: node = node->parent;
3651: }
1.82 daniel 3652: return(NULL);
3653: }
3654:
3655: /**
3656: * xmlNewReconciliedNs
3657: * @doc: the document
3658: * @tree: a node expected to hold the new namespace
3659: * @ns: the original namespace
3660: *
3661: * This function tries to locate a namespace definition in a tree
3662: * ancestors, or create a new namespace definition node similar to
3663: * @ns trying to reuse the same prefix. However if the given prefix is
3664: * null (default namespace) or reused within the subtree defined by
3665: * @tree or on one of its ancestors then a new prefix is generated.
3666: * Returns the (new) namespace definition or NULL in case of error
3667: */
3668: xmlNsPtr
3669: xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3670: xmlNsPtr def;
3671: xmlChar prefix[50];
3672: int counter = 1;
3673:
3674: if (tree == NULL) {
3675: #ifdef DEBUG_TREE
1.134 veillard 3676: xmlGenericError(xmlGenericErrorContext,
3677: "xmlNewReconciliedNs : tree == NULL\n");
1.82 daniel 3678: #endif
3679: return(NULL);
3680: }
3681: if (ns == NULL) {
3682: #ifdef DEBUG_TREE
1.134 veillard 3683: xmlGenericError(xmlGenericErrorContext,
3684: "xmlNewReconciliedNs : ns == NULL\n");
1.82 daniel 3685: #endif
3686: return(NULL);
3687: }
3688: /*
3689: * Search an existing namespace definition inherited.
3690: */
3691: def = xmlSearchNsByHref(doc, tree, ns->href);
3692: if (def != NULL)
3693: return(def);
3694:
3695: /*
3696: * Find a close prefix which is not already in use.
3697: * Let's strip namespace prefixes longer than 20 chars !
3698: */
3699: sprintf((char *) prefix, "%.20s", ns->prefix);
3700: def = xmlSearchNs(doc, tree, prefix);
3701: while (def != NULL) {
3702: if (counter > 1000) return(NULL);
3703: sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3704: def = xmlSearchNs(doc, tree, prefix);
3705: }
3706:
3707: /*
3708: * Ok, now we are ready to create a new one.
3709: */
3710: def = xmlNewNs(tree, ns->href, prefix);
3711: return(def);
3712: }
3713:
3714: /**
3715: * xmlReconciliateNs
3716: * @doc: the document
3717: * @tree: a node defining the subtree to reconciliate
3718: *
3719: * This function checks that all the namespaces declared within the given
3720: * tree are properly declared. This is needed for example after Copy or Cut
3721: * and then paste operations. The subtree may still hold pointers to
3722: * namespace declarations outside the subtree or invalid/masked. As much
3723: * as possible the function try tu reuse the existing namespaces found in
3724: * the new environment. If not possible the new namespaces are redeclared
3725: * on @tree at the top of the given subtree.
3726: * Returns the number of namespace declarations created or -1 in case of error.
3727: */
3728: int
3729: xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3730: xmlNsPtr *oldNs = NULL;
3731: xmlNsPtr *newNs = NULL;
3732: int sizeCache = 0;
3733: int nbCache = 0;
3734:
3735: xmlNsPtr n;
3736: xmlNodePtr node = tree;
3737: xmlAttrPtr attr;
3738: int ret = 0, i;
3739:
3740: while (node != NULL) {
3741: /*
3742: * Reconciliate the node namespace
3743: */
3744: if (node->ns != NULL) {
3745: /*
3746: * initialize the cache if needed
3747: */
3748: if (sizeCache == 0) {
3749: sizeCache = 10;
3750: oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3751: sizeof(xmlNsPtr));
3752: if (oldNs == NULL) {
1.134 veillard 3753: xmlGenericError(xmlGenericErrorContext,
3754: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3755: return(-1);
3756: }
3757: newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3758: sizeof(xmlNsPtr));
3759: if (newNs == NULL) {
1.134 veillard 3760: xmlGenericError(xmlGenericErrorContext,
3761: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3762: xmlFree(oldNs);
3763: return(-1);
3764: }
3765: }
3766: for (i = 0;i < nbCache;i++) {
3767: if (oldNs[i] == node->ns) {
3768: node->ns = newNs[i];
3769: break;
3770: }
3771: }
3772: if (i == nbCache) {
3773: /*
3774: * Ok we need to recreate a new namespace definition
3775: */
3776: n = xmlNewReconciliedNs(doc, tree, node->ns);
3777: if (n != NULL) { /* :-( what if else ??? */
3778: /*
3779: * check if we need to grow the cache buffers.
3780: */
3781: if (sizeCache <= nbCache) {
3782: sizeCache *= 2;
3783: oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3784: sizeof(xmlNsPtr));
3785: if (oldNs == NULL) {
1.134 veillard 3786: xmlGenericError(xmlGenericErrorContext,
3787: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3788: xmlFree(newNs);
3789: return(-1);
3790: }
3791: newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3792: sizeof(xmlNsPtr));
3793: if (newNs == NULL) {
1.134 veillard 3794: xmlGenericError(xmlGenericErrorContext,
3795: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3796: xmlFree(oldNs);
3797: return(-1);
3798: }
3799: }
3800: newNs[nbCache] = n;
3801: oldNs[nbCache++] = node->ns;
3802: node->ns = n;
3803: }
3804: }
3805: }
3806: /*
3807: * now check for namespace hold by attributes on the node.
3808: */
3809: attr = node->properties;
3810: while (attr != NULL) {
3811: if (attr->ns != NULL) {
3812: /*
3813: * initialize the cache if needed
3814: */
3815: if (sizeCache == 0) {
3816: sizeCache = 10;
3817: oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3818: sizeof(xmlNsPtr));
3819: if (oldNs == NULL) {
1.134 veillard 3820: xmlGenericError(xmlGenericErrorContext,
3821: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3822: return(-1);
3823: }
3824: newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3825: sizeof(xmlNsPtr));
3826: if (newNs == NULL) {
1.134 veillard 3827: xmlGenericError(xmlGenericErrorContext,
3828: "xmlReconciliateNs : memory pbm\n");
1.82 daniel 3829: xmlFree(oldNs);
3830: return(-1);
3831: }
3832: }
3833: for (i = 0;i < nbCache;i++) {
3834: if (oldNs[i] == attr->ns) {
3835: node->ns = newNs[i];
3836: break;
3837: }
3838: }
3839: if (i == nbCache) {
3840: /*
3841: * Ok we need to recreate a new namespace definition
3842: */
3843: n = xmlNewReconciliedNs(doc, tree, attr->ns);
3844: if (n != NULL) { /* :-( what if else ??? */
3845: /*
3846: * check if we need to grow the cache buffers.
3847: */
3848: if (sizeCache <= nbCache) {
3849: sizeCache *= 2;
3850: oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3851: sizeof(xmlNsPtr));
3852: if (oldNs == NULL) {
1.134 veillard 3853: xmlGenericError(xmlGenericErrorContext,
1.82 daniel 3854: "xmlReconciliateNs : memory pbm\n");
3855: xmlFree(newNs);
3856: return(-1);
3857: }
3858: newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3859: sizeof(xmlNsPtr));
3860: if (newNs == NULL) {
1.134 veillard 3861: xmlGenericError(xmlGenericErrorContext,
1.82 daniel 3862: "xmlReconciliateNs : memory pbm\n");
3863: xmlFree(oldNs);
3864: return(-1);
3865: }
3866: }
3867: newNs[nbCache] = n;
3868: oldNs[nbCache++] = attr->ns;
3869: attr->ns = n;
3870: }
3871: }
3872: }
3873: attr = attr->next;
3874: }
3875:
3876: /*
3877: * Browse the full subtree, deep first
3878: */
1.90 daniel 3879: if (node->children != NULL) {
1.82 daniel 3880: /* deep first */
1.90 daniel 3881: node = node->children;
1.82 daniel 3882: } else if ((node != tree) && (node->next != NULL)) {
3883: /* then siblings */
3884: node = node->next;
3885: } else if (node != tree) {
3886: /* go up to parents->next if needed */
3887: while (node != tree) {
3888: if (node->parent != NULL)
3889: node = node->parent;
3890: if ((node != tree) && (node->next != NULL)) {
3891: node = node->next;
3892: break;
3893: }
3894: if (node->parent == NULL) {
3895: node = NULL;
3896: break;
3897: }
3898: }
3899: /* exit condition */
3900: if (node == tree)
3901: node = NULL;
1.19 daniel 3902: }
1.3 veillard 3903: }
1.82 daniel 3904: return(ret);
1.3 veillard 3905: }
3906:
1.23 daniel 3907: /**
1.116 veillard 3908: * xmlHasProp:
3909: * @node: the node
3910: * @name: the attribute name
3911: *
3912: * Search an attribute associated to a node
3913: * This function also looks in DTD attribute declaration for #FIXED or
3914: * default declaration values unless DTD use has been turned off.
3915: *
3916: * Returns the attribute or the attribute declaration or NULL if
3917: * neither was found.
3918: */
3919: xmlAttrPtr
3920: xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3921: xmlAttrPtr prop;
3922: xmlDocPtr doc;
3923:
3924: if ((node == NULL) || (name == NULL)) return(NULL);
3925: /*
3926: * Check on the properties attached to the node
3927: */
3928: prop = node->properties;
3929: while (prop != NULL) {
1.128 veillard 3930: if (xmlStrEqual(prop->name, name)) {
1.116 veillard 3931: return(prop);
3932: }
3933: prop = prop->next;
3934: }
3935: if (!xmlCheckDTD) return(NULL);
3936:
3937: /*
3938: * Check if there is a default declaration in the internal
3939: * or external subsets
3940: */
3941: doc = node->doc;
3942: if (doc != NULL) {
3943: xmlAttributePtr attrDecl;
3944: if (doc->intSubset != NULL) {
3945: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3946: if ((attrDecl == NULL) && (doc->extSubset != NULL))
3947: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3948: if (attrDecl != NULL)
3949: return((xmlAttrPtr) attrDecl);
3950: }
3951: }
3952: return(NULL);
3953: }
3954:
3955: /**
1.23 daniel 3956: * xmlGetProp:
3957: * @node: the node
3958: * @name: the attribute name
3959: *
3960: * Search and get the value of an attribute associated to a node
3961: * This does the entity substitution.
1.74 daniel 3962: * This function looks in DTD attribute declaration for #FIXED or
3963: * default declaration values unless DTD use has been turned off.
3964: *
1.36 daniel 3965: * Returns the attribute value or NULL if not found.
1.69 daniel 3966: * It's up to the caller to free the memory.
1.9 veillard 3967: */
1.69 daniel 3968: xmlChar *
3969: xmlGetProp(xmlNodePtr node, const xmlChar *name) {
1.74 daniel 3970: xmlAttrPtr prop;
3971: xmlDocPtr doc;
1.9 veillard 3972:
1.74 daniel 3973: if ((node == NULL) || (name == NULL)) return(NULL);
3974: /*
3975: * Check on the properties attached to the node
3976: */
3977: prop = node->properties;
1.9 veillard 3978: while (prop != NULL) {
1.128 veillard 3979: if (xmlStrEqual(prop->name, name)) {
1.61 daniel 3980: xmlChar *ret;
1.34 daniel 3981:
1.90 daniel 3982: ret = xmlNodeListGetString(node->doc, prop->children, 1);
1.61 daniel 3983: if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1.34 daniel 3984: return(ret);
3985: }
1.9 veillard 3986: prop = prop->next;
3987: }
1.74 daniel 3988: if (!xmlCheckDTD) return(NULL);
3989:
3990: /*
3991: * Check if there is a default declaration in the internal
3992: * or external subsets
3993: */
3994: doc = node->doc;
3995: if (doc != NULL) {
3996: xmlAttributePtr attrDecl;
3997: if (doc->intSubset != NULL) {
3998: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3999: if ((attrDecl == NULL) && (doc->extSubset != NULL))
4000: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
1.86 daniel 4001: if (attrDecl != NULL)
4002: return(xmlStrdup(attrDecl->defaultValue));
1.74 daniel 4003: }
4004: }
1.10 veillard 4005: return(NULL);
1.13 daniel 4006: }
4007:
1.23 daniel 4008: /**
1.73 daniel 4009: * xmlGetNsProp:
4010: * @node: the node
4011: * @name: the attribute name
4012: * @namespace: the URI of the namespace
4013: *
4014: * Search and get the value of an attribute associated to a node
4015: * This attribute has to be anchored in the namespace specified.
4016: * This does the entity substitution.
1.74 daniel 4017: * This function looks in DTD attribute declaration for #FIXED or
4018: * default declaration values unless DTD use has been turned off.
1.73 daniel 4019: *
4020: * Returns the attribute value or NULL if not found.
4021: * It's up to the caller to free the memory.
4022: */
4023: xmlChar *
4024: xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4025: xmlAttrPtr prop = node->properties;
1.74 daniel 4026: xmlDocPtr doc;
4027: xmlNsPtr ns;
1.73 daniel 4028:
4029: if (namespace == NULL)
4030: return(xmlGetProp(node, name));
4031: while (prop != NULL) {
1.79 daniel 4032: /*
4033: * One need to have
4034: * - same attribute names
4035: * - and the attribute carrying that namespace
4036: * or
4037: * no namespace on the attribute and the element carrying it
4038: */
1.128 veillard 4039: if ((xmlStrEqual(prop->name, name)) &&
1.79 daniel 4040: (((prop->ns == NULL) && (node->ns != NULL) &&
1.128 veillard 4041: (xmlStrEqual(node->ns->href, namespace))) ||
4042: ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
1.73 daniel 4043: xmlChar *ret;
4044:
1.90 daniel 4045: ret = xmlNodeListGetString(node->doc, prop->children, 1);
1.73 daniel 4046: if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4047: return(ret);
4048: }
4049: prop = prop->next;
4050: }
1.74 daniel 4051: if (!xmlCheckDTD) return(NULL);
4052:
4053: /*
4054: * Check if there is a default declaration in the internal
4055: * or external subsets
4056: */
4057: doc = node->doc;
4058: if (doc != NULL) {
4059: xmlAttributePtr attrDecl;
4060: if (doc->intSubset != NULL) {
4061: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4062: if ((attrDecl == NULL) && (doc->extSubset != NULL))
4063: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4064:
4065: if (attrDecl->prefix != NULL) {
4066: /*
4067: * The DTD declaration only allows a prefix search
4068: */
4069: ns = xmlSearchNs(doc, node, attrDecl->prefix);
1.128 veillard 4070: if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
1.74 daniel 4071: return(xmlStrdup(attrDecl->defaultValue));
4072: }
4073: }
4074: }
1.73 daniel 4075: return(NULL);
4076: }
4077:
4078: /**
1.23 daniel 4079: * xmlSetProp:
4080: * @node: the node
4081: * @name: the attribute name
4082: * @value: the attribute value
4083: *
4084: * Set (or reset) an attribute carried by a node.
1.36 daniel 4085: * Returns the attribute pointer.
1.13 daniel 4086: */
1.28 daniel 4087: xmlAttrPtr
1.61 daniel 4088: xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1.20 daniel 4089: xmlAttrPtr prop = node->properties;
1.13 daniel 4090:
4091: while (prop != NULL) {
1.128 veillard 4092: if (xmlStrEqual(prop->name, name)) {
1.90 daniel 4093: if (prop->children != NULL)
4094: xmlFreeNodeList(prop->children);
4095: prop->children = NULL;
1.140 veillard 4096: prop->last = NULL;
1.67 daniel 4097: if (value != NULL) {
4098: xmlChar *buffer;
1.94 daniel 4099: xmlNodePtr tmp;
4100:
1.67 daniel 4101: buffer = xmlEncodeEntitiesReentrant(node->doc, value);
1.90 daniel 4102: prop->children = xmlStringGetNodeList(node->doc, buffer);
1.140 veillard 4103: prop->last = NULL;
1.94 daniel 4104: tmp = prop->children;
4105: while (tmp != NULL) {
4106: tmp->parent = (xmlNodePtr) prop;
4107: if (tmp->next == NULL)
4108: prop->last = tmp;
4109: tmp = tmp->next;
4110: }
1.67 daniel 4111: xmlFree(buffer);
4112: }
1.13 daniel 4113: return(prop);
4114: }
4115: prop = prop->next;
4116: }
4117: prop = xmlNewProp(node, name, value);
4118: return(prop);
1.9 veillard 4119: }
4120:
1.23 daniel 4121: /**
4122: * xmlNodeIsText:
4123: * @node: the node
4124: *
4125: * Is this node a Text node ?
1.36 daniel 4126: * Returns 1 yes, 0 no
1.21 daniel 4127: */
1.28 daniel 4128: int
4129: xmlNodeIsText(xmlNodePtr node) {
1.21 daniel 4130: if (node == NULL) return(0);
4131:
1.23 daniel 4132: if (node->type == XML_TEXT_NODE) return(1);
1.21 daniel 4133: return(0);
4134: }
4135:
1.23 daniel 4136: /**
1.99 daniel 4137: * xmlIsBlankNode:
4138: * @node: the node
4139: *
1.113 veillard 4140: * Checks whether this node is an empty or whitespace only
4141: * (and possibly ignorable) text-node.
4142: *
1.99 daniel 4143: * Returns 1 yes, 0 no
4144: */
4145: int
4146: xmlIsBlankNode(xmlNodePtr node) {
1.137 veillard 4147: const xmlChar *cur;
1.99 daniel 4148: if (node == NULL) return(0);
4149:
4150: if (node->type != XML_TEXT_NODE) return(0);
1.129 veillard 4151: if (node->content == NULL) return(1);
1.137 veillard 4152: #ifndef XML_USE_BUFFER_CONTENT
1.99 daniel 4153: cur = node->content;
1.137 veillard 4154: #else
4155: cur = xmlBufferContent(node->content);
4156: #endif
1.99 daniel 4157: while (*cur != 0) {
4158: if (!IS_BLANK(*cur)) return(0);
4159: cur++;
4160: }
4161:
4162: return(1);
4163: }
4164:
4165: /**
1.36 daniel 4166: * xmlTextConcat:
1.23 daniel 4167: * @node: the node
4168: * @content: the content
4169: * @len: @content lenght
4170: *
4171: * Concat the given string at the end of the existing node content
1.21 daniel 4172: */
1.23 daniel 4173:
1.28 daniel 4174: void
1.61 daniel 4175: xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
1.21 daniel 4176: if (node == NULL) return;
4177:
1.82 daniel 4178: if ((node->type != XML_TEXT_NODE) &&
4179: (node->type != XML_CDATA_SECTION_NODE)) {
1.86 daniel 4180: #ifdef DEBUG_TREE
1.134 veillard 4181: xmlGenericError(xmlGenericErrorContext,
4182: "xmlTextConcat: node is not text nor cdata\n");
1.86 daniel 4183: #endif
1.21 daniel 4184: return;
4185: }
1.70 daniel 4186: #ifndef XML_USE_BUFFER_CONTENT
1.21 daniel 4187: node->content = xmlStrncat(node->content, content, len);
1.70 daniel 4188: #else
4189: xmlBufferAdd(node->content, content, len);
4190: #endif
1.21 daniel 4191: }
4192:
1.1 veillard 4193: /************************************************************************
4194: * *
1.8 veillard 4195: * Output : to a FILE or in memory *
1.1 veillard 4196: * *
4197: ************************************************************************/
4198:
1.38 daniel 4199: #define BASE_BUFFER_SIZE 4000
1.8 veillard 4200:
1.23 daniel 4201: /**
1.38 daniel 4202: * xmlBufferCreate:
4203: *
4204: * routine to create an XML buffer.
4205: * returns the new structure.
4206: */
4207: xmlBufferPtr
4208: xmlBufferCreate(void) {
4209: xmlBufferPtr ret;
4210:
1.57 daniel 4211: ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
1.38 daniel 4212: if (ret == NULL) {
1.134 veillard 4213: xmlGenericError(xmlGenericErrorContext,
4214: "xmlBufferCreate : out of memory!\n");
1.38 daniel 4215: return(NULL);
4216: }
4217: ret->use = 0;
4218: ret->size = BASE_BUFFER_SIZE;
1.72 daniel 4219: ret->alloc = xmlBufferAllocScheme;
1.61 daniel 4220: ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
1.38 daniel 4221: if (ret->content == NULL) {
1.134 veillard 4222: xmlGenericError(xmlGenericErrorContext,
4223: "xmlBufferCreate : out of memory!\n");
1.57 daniel 4224: xmlFree(ret);
1.38 daniel 4225: return(NULL);
4226: }
4227: ret->content[0] = 0;
4228: return(ret);
4229: }
4230:
4231: /**
1.70 daniel 4232: * xmlBufferCreateSize:
4233: * @size: initial size of buffer
4234: *
4235: * routine to create an XML buffer.
4236: * returns the new structure.
4237: */
4238: xmlBufferPtr
4239: xmlBufferCreateSize(size_t size) {
4240: xmlBufferPtr ret;
4241:
4242: ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4243: if (ret == NULL) {
1.134 veillard 4244: xmlGenericError(xmlGenericErrorContext,
4245: "xmlBufferCreate : out of memory!\n");
1.70 daniel 4246: return(NULL);
4247: }
4248: ret->use = 0;
1.72 daniel 4249: ret->alloc = xmlBufferAllocScheme;
1.70 daniel 4250: ret->size = (size ? size+2 : 0); /* +1 for ending null */
1.72 daniel 4251: if (ret->size){
1.70 daniel 4252: ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4253: if (ret->content == NULL) {
1.134 veillard 4254: xmlGenericError(xmlGenericErrorContext,
4255: "xmlBufferCreate : out of memory!\n");
1.70 daniel 4256: xmlFree(ret);
4257: return(NULL);
4258: }
4259: ret->content[0] = 0;
4260: } else
4261: ret->content = NULL;
4262: return(ret);
4263: }
4264:
4265: /**
1.104 daniel 4266: * xmlBufferSetAllocationScheme:
1.70 daniel 4267: * @buf: the buffer to free
4268: * @scheme: allocation scheme to use
4269: *
4270: * Sets the allocation scheme for this buffer
4271: */
4272: void
4273: xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4274: xmlBufferAllocationScheme scheme) {
4275: if (buf == NULL) {
1.86 daniel 4276: #ifdef DEBUG_BUFFER
1.134 veillard 4277: xmlGenericError(xmlGenericErrorContext,
4278: "xmlBufferSetAllocationScheme: buf == NULL\n");
1.86 daniel 4279: #endif
1.70 daniel 4280: return;
4281: }
4282:
4283: buf->alloc = scheme;
4284: }
4285:
4286: /**
1.38 daniel 4287: * xmlBufferFree:
4288: * @buf: the buffer to free
4289: *
4290: * Frees an XML buffer.
4291: */
4292: void
4293: xmlBufferFree(xmlBufferPtr buf) {
4294: if (buf == NULL) {
1.86 daniel 4295: #ifdef DEBUG_BUFFER
1.134 veillard 4296: xmlGenericError(xmlGenericErrorContext,
4297: "xmlBufferFree: buf == NULL\n");
1.86 daniel 4298: #endif
1.38 daniel 4299: return;
4300: }
1.71 daniel 4301: if (buf->content != NULL) {
1.70 daniel 4302: #ifndef XML_USE_BUFFER_CONTENT
1.38 daniel 4303: memset(buf->content, -1, BASE_BUFFER_SIZE);
1.70 daniel 4304: #else
4305: memset(buf->content, -1, buf->size);
4306: #endif
1.57 daniel 4307: xmlFree(buf->content);
1.38 daniel 4308: }
4309: memset(buf, -1, sizeof(xmlBuffer));
1.57 daniel 4310: xmlFree(buf);
1.38 daniel 4311: }
4312:
4313: /**
1.47 daniel 4314: * xmlBufferEmpty:
4315: * @buf: the buffer
4316: *
4317: * empty a buffer.
4318: */
4319: void
4320: xmlBufferEmpty(xmlBufferPtr buf) {
1.124 veillard 4321: if (buf->content == NULL) return;
1.47 daniel 4322: buf->use = 0;
4323: memset(buf->content, -1, buf->size);/* just for debug */
4324: }
4325:
4326: /**
4327: * xmlBufferShrink:
4328: * @buf: the buffer to dump
1.61 daniel 4329: * @len: the number of xmlChar to remove
1.47 daniel 4330: *
4331: * Remove the beginning of an XML buffer.
4332: *
1.61 daniel 4333: * Returns the number of xmlChar removed, or -1 in case of failure.
1.47 daniel 4334: */
4335: int
1.127 veillard 4336: xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
1.47 daniel 4337: if (len == 0) return(0);
4338: if (len > buf->use) return(-1);
4339:
4340: buf->use -= len;
1.61 daniel 4341: memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
1.47 daniel 4342:
4343: buf->content[buf->use] = 0;
4344: return(len);
4345: }
4346:
4347: /**
1.105 daniel 4348: * xmlBufferGrow:
4349: * @buf: the buffer
1.148 veillard 4350: * @len: the minimum free size to allocate
1.105 daniel 4351: *
4352: * Grow the available space of an XML buffer.
4353: *
4354: * Returns the new available space or -1 in case of error
4355: */
4356: int
1.127 veillard 4357: xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
1.105 daniel 4358: int size;
4359: xmlChar *newbuf;
4360:
1.148 veillard 4361: if (len + buf->use < buf->size) return(0);
1.105 daniel 4362:
1.109 daniel 4363: size = buf->use + len + 100;
1.105 daniel 4364:
1.112 veillard 4365: newbuf = (xmlChar *) xmlRealloc(buf->content, size);
1.105 daniel 4366: if (newbuf == NULL) return(-1);
4367: buf->content = newbuf;
4368: buf->size = size;
4369: return(buf->size - buf->use);
4370: }
4371:
4372: /**
1.38 daniel 4373: * xmlBufferDump:
4374: * @file: the file output
4375: * @buf: the buffer to dump
4376: *
4377: * Dumps an XML buffer to a FILE *.
1.61 daniel 4378: * Returns the number of xmlChar written
1.38 daniel 4379: */
4380: int
4381: xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4382: int ret;
4383:
4384: if (buf == NULL) {
1.86 daniel 4385: #ifdef DEBUG_BUFFER
1.134 veillard 4386: xmlGenericError(xmlGenericErrorContext,
4387: "xmlBufferDump: buf == NULL\n");
1.86 daniel 4388: #endif
1.38 daniel 4389: return(0);
4390: }
4391: if (buf->content == NULL) {
1.86 daniel 4392: #ifdef DEBUG_BUFFER
1.134 veillard 4393: xmlGenericError(xmlGenericErrorContext,
4394: "xmlBufferDump: buf->content == NULL\n");
1.86 daniel 4395: #endif
1.38 daniel 4396: return(0);
4397: }
4398: if (file == NULL) file = stdout;
1.61 daniel 4399: ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
1.38 daniel 4400: return(ret);
4401: }
4402:
4403: /**
1.70 daniel 4404: * xmlBufferContent:
4405: * @buf: the buffer to resize
4406: *
4407: * Returns the internal content
4408: */
4409:
4410: const xmlChar*
4411: xmlBufferContent(const xmlBufferPtr buf)
4412: {
4413: if(!buf)
4414: return NULL;
4415:
4416: return buf->content;
4417: }
4418:
4419: /**
4420: * xmlBufferLength:
4421: * @buf: the buffer
4422: *
4423: * Returns the length of data in the internal content
4424: */
4425:
4426: int
4427: xmlBufferLength(const xmlBufferPtr buf)
4428: {
4429: if(!buf)
4430: return 0;
4431:
4432: return buf->use;
4433: }
4434:
4435: /**
4436: * xmlBufferResize:
4437: * @buf: the buffer to resize
1.127 veillard 4438: * @size: the desired size
1.70 daniel 4439: *
1.127 veillard 4440: * Resize a buffer to accomodate minimum size of @size.
1.70 daniel 4441: *
4442: * Returns 0 in case of problems, 1 otherwise
4443: */
4444: int
1.127 veillard 4445: xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1.70 daniel 4446: {
1.127 veillard 4447: unsigned int newSize;
1.70 daniel 4448: xmlChar* rebuf = NULL;
4449:
1.127 veillard 4450: /*take care of empty case*/
4451: newSize = (buf->size ? buf->size*2 : size);
4452:
1.70 daniel 4453: /* Don't resize if we don't have to */
1.127 veillard 4454: if (size < buf->size)
1.70 daniel 4455: return 1;
4456:
4457: /* figure out new size */
1.127 veillard 4458: switch (buf->alloc){
1.70 daniel 4459: case XML_BUFFER_ALLOC_DOUBLEIT:
1.127 veillard 4460: while (size > newSize) newSize *= 2;
1.70 daniel 4461: break;
4462: case XML_BUFFER_ALLOC_EXACT:
4463: newSize = size+10;
4464: break;
4465: default:
4466: newSize = size+10;
4467: break;
4468: }
4469:
4470: if (buf->content == NULL)
4471: rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4472: else
4473: rebuf = (xmlChar *) xmlRealloc(buf->content,
4474: newSize * sizeof(xmlChar));
4475: if (rebuf == NULL) {
1.134 veillard 4476: xmlGenericError(xmlGenericErrorContext,
4477: "xmlBufferAdd : out of memory!\n");
1.70 daniel 4478: return 0;
4479: }
4480: buf->content = rebuf;
4481: buf->size = newSize;
4482:
4483: return 1;
4484: }
1.127 veillard 4485:
1.70 daniel 4486: /**
1.38 daniel 4487: * xmlBufferAdd:
4488: * @buf: the buffer to dump
1.61 daniel 4489: * @str: the xmlChar string
4490: * @len: the number of xmlChar to add
1.38 daniel 4491: *
1.74 daniel 4492: * Add a string range to an XML buffer. if len == -1, the lenght of
4493: * str is recomputed.
1.38 daniel 4494: */
4495: void
1.61 daniel 4496: xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
1.127 veillard 4497: unsigned int needSize;
1.38 daniel 4498:
4499: if (str == NULL) {
1.86 daniel 4500: #ifdef DEBUG_BUFFER
1.134 veillard 4501: xmlGenericError(xmlGenericErrorContext,
4502: "xmlBufferAdd: str == NULL\n");
1.86 daniel 4503: #endif
1.38 daniel 4504: return;
4505: }
1.74 daniel 4506: if (len < -1) {
1.86 daniel 4507: #ifdef DEBUG_BUFFER
1.134 veillard 4508: xmlGenericError(xmlGenericErrorContext,
4509: "xmlBufferAdd: len < 0\n");
1.86 daniel 4510: #endif
1.74 daniel 4511: return;
4512: }
4513: if (len == 0) return;
1.70 daniel 4514:
1.82 daniel 4515: if (len < 0)
1.89 daniel 4516: len = xmlStrlen(str);
1.70 daniel 4517:
1.47 daniel 4518: if (len <= 0) return;
4519:
1.70 daniel 4520: needSize = buf->use + len + 2;
1.127 veillard 4521: if (needSize > buf->size){
4522: if (!xmlBufferResize(buf, needSize)){
1.134 veillard 4523: xmlGenericError(xmlGenericErrorContext,
4524: "xmlBufferAdd : out of memory!\n");
1.70 daniel 4525: return;
4526: }
4527: }
1.47 daniel 4528:
1.70 daniel 4529: memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
1.47 daniel 4530: buf->use += len;
4531: buf->content[buf->use] = 0;
1.38 daniel 4532: }
4533:
4534: /**
1.109 daniel 4535: * xmlBufferAddHead:
4536: * @buf: the buffer
4537: * @str: the xmlChar string
4538: * @len: the number of xmlChar to add
4539: *
4540: * Add a string range to the beginning of an XML buffer.
4541: * if len == -1, the lenght of @str is recomputed.
4542: */
4543: void
4544: xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
1.127 veillard 4545: unsigned int needSize;
1.109 daniel 4546:
4547: if (str == NULL) {
4548: #ifdef DEBUG_BUFFER
1.134 veillard 4549: xmlGenericError(xmlGenericErrorContext,
4550: "xmlBufferAdd: str == NULL\n");
1.109 daniel 4551: #endif
4552: return;
4553: }
4554: if (len < -1) {
4555: #ifdef DEBUG_BUFFER
1.134 veillard 4556: xmlGenericError(xmlGenericErrorContext,
4557: "xmlBufferAdd: len < 0\n");
1.109 daniel 4558: #endif
4559: return;
4560: }
4561: if (len == 0) return;
4562:
4563: if (len < 0)
4564: len = xmlStrlen(str);
4565:
4566: if (len <= 0) return;
4567:
4568: needSize = buf->use + len + 2;
1.127 veillard 4569: if (needSize > buf->size){
4570: if (!xmlBufferResize(buf, needSize)){
1.134 veillard 4571: xmlGenericError(xmlGenericErrorContext,
4572: "xmlBufferAddHead : out of memory!\n");
1.109 daniel 4573: return;
4574: }
4575: }
4576:
4577: memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4578: memmove(&buf->content[0], str, len * sizeof(xmlChar));
4579: buf->use += len;
4580: buf->content[buf->use] = 0;
4581: }
4582:
4583: /**
1.38 daniel 4584: * xmlBufferCat:
4585: * @buf: the buffer to dump
1.61 daniel 4586: * @str: the xmlChar string
1.23 daniel 4587: *
1.38 daniel 4588: * Append a zero terminated string to an XML buffer.
1.23 daniel 4589: */
1.28 daniel 4590: void
1.61 daniel 4591: xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
1.70 daniel 4592: if (str != NULL)
4593: xmlBufferAdd(buf, str, -1);
1.8 veillard 4594: }
4595:
1.23 daniel 4596: /**
1.38 daniel 4597: * xmlBufferCCat:
4598: * @buf: the buffer to dump
4599: * @str: the C char string
1.23 daniel 4600: *
1.38 daniel 4601: * Append a zero terminated C string to an XML buffer.
1.23 daniel 4602: */
1.28 daniel 4603: void
1.38 daniel 4604: xmlBufferCCat(xmlBufferPtr buf, const char *str) {
1.21 daniel 4605: const char *cur;
1.8 veillard 4606:
1.38 daniel 4607: if (str == NULL) {
1.86 daniel 4608: #ifdef DEBUG_BUFFER
1.134 veillard 4609: xmlGenericError(xmlGenericErrorContext,
4610: "xmlBufferAdd: str == NULL\n");
1.86 daniel 4611: #endif
1.38 daniel 4612: return;
4613: }
4614: for (cur = str;*cur != 0;cur++) {
4615: if (buf->use + 10 >= buf->size) {
1.127 veillard 4616: if (!xmlBufferResize(buf, buf->use+10)){
1.134 veillard 4617: xmlGenericError(xmlGenericErrorContext,
4618: "xmlBufferCCat : out of memory!\n");
1.70 daniel 4619: return;
4620: }
4621: }
1.38 daniel 4622: buf->content[buf->use++] = *cur;
1.8 veillard 4623: }
4624: }
4625:
1.23 daniel 4626: /**
1.38 daniel 4627: * xmlBufferWriteCHAR:
4628: * @buf: the XML buffer
4629: * @string: the string to add
4630: *
1.145 veillard 4631: * routine which manages and grows an output buffer. This one adds
1.61 daniel 4632: * xmlChars at the end of the buffer.
1.38 daniel 4633: */
4634: void
1.145 veillard 4635: #ifdef VMS
4636: xmlBufferWriteXmlCHAR
4637: #else
4638: xmlBufferWriteCHAR
4639: #endif
4640: (xmlBufferPtr buf, const xmlChar *string) {
1.38 daniel 4641: xmlBufferCat(buf, string);
4642: }
4643:
4644: /**
4645: * xmlBufferWriteChar:
1.42 daniel 4646: * @buf: the XML buffer output
1.38 daniel 4647: * @string: the string to add
4648: *
4649: * routine which manage and grows an output buffer. This one add
4650: * C chars at the end of the array.
4651: */
4652: void
4653: xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4654: xmlBufferCCat(buf, string);
4655: }
4656:
4657:
4658: /**
1.43 daniel 4659: * xmlBufferWriteQuotedString:
4660: * @buf: the XML buffer output
4661: * @string: the string to add
4662: *
4663: * routine which manage and grows an output buffer. This one writes
1.61 daniel 4664: * a quoted or double quoted xmlChar string, checking first if it holds
1.43 daniel 4665: * quote or double-quotes internally
4666: */
4667: void
1.61 daniel 4668: xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
1.53 daniel 4669: if (xmlStrchr(string, '"')) {
4670: if (xmlStrchr(string, '\'')) {
1.86 daniel 4671: #ifdef DEBUG_BUFFER
1.134 veillard 4672: xmlGenericError(xmlGenericErrorContext,
1.43 daniel 4673: "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
1.86 daniel 4674: #endif
1.43 daniel 4675: }
4676: xmlBufferCCat(buf, "'");
4677: xmlBufferCat(buf, string);
4678: xmlBufferCCat(buf, "'");
4679: } else {
4680: xmlBufferCCat(buf, "\"");
4681: xmlBufferCat(buf, string);
4682: xmlBufferCCat(buf, "\"");
4683: }
4684: }
4685:
4686:
1.106 daniel 4687: /************************************************************************
4688: * *
4689: * Dumping XML tree content to a simple buffer *
4690: * *
4691: ************************************************************************/
4692:
1.125 veillard 4693: void
1.99 daniel 4694: xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4695: int format);
4696: static void
4697: xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4698: int format);
4699: void
4700: htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4701:
1.43 daniel 4702: /**
1.23 daniel 4703: * xmlNsDump:
1.42 daniel 4704: * @buf: the XML buffer output
1.23 daniel 4705: * @cur: a namespace
4706: *
1.19 daniel 4707: * Dump a local Namespace definition.
1.23 daniel 4708: * Should be called in the context of attributes dumps.
1.19 daniel 4709: */
1.28 daniel 4710: static void
1.38 daniel 4711: xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
1.19 daniel 4712: if (cur == NULL) {
1.86 daniel 4713: #ifdef DEBUG_TREE
1.134 veillard 4714: xmlGenericError(xmlGenericErrorContext,
4715: "xmlNsDump : Ns == NULL\n");
1.86 daniel 4716: #endif
1.19 daniel 4717: return;
4718: }
4719: if (cur->type == XML_LOCAL_NAMESPACE) {
4720: /* Within the context of an element attributes */
1.16 daniel 4721: if (cur->prefix != NULL) {
1.38 daniel 4722: xmlBufferWriteChar(buf, " xmlns:");
4723: xmlBufferWriteCHAR(buf, cur->prefix);
1.19 daniel 4724: } else
1.38 daniel 4725: xmlBufferWriteChar(buf, " xmlns");
1.43 daniel 4726: xmlBufferWriteChar(buf, "=");
4727: xmlBufferWriteQuotedString(buf, cur->href);
1.19 daniel 4728: }
4729: }
4730:
1.23 daniel 4731: /**
4732: * xmlNsListDump:
1.42 daniel 4733: * @buf: the XML buffer output
1.23 daniel 4734: * @cur: the first namespace
4735: *
4736: * Dump a list of local Namespace definitions.
4737: * Should be called in the context of attributes dumps.
1.19 daniel 4738: */
1.28 daniel 4739: static void
1.38 daniel 4740: xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
1.19 daniel 4741: while (cur != NULL) {
1.38 daniel 4742: xmlNsDump(buf, cur);
1.19 daniel 4743: cur = cur->next;
1.8 veillard 4744: }
1.1 veillard 4745: }
4746:
1.23 daniel 4747: /**
4748: * xmlDtdDump:
1.42 daniel 4749: * @buf: the XML buffer output
1.23 daniel 4750: * @doc: the document
4751: *
4752: * Dump the XML document DTD, if any.
1.17 daniel 4753: */
1.28 daniel 4754: static void
1.92 daniel 4755: xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4756: if (dtd == NULL) {
1.86 daniel 4757: #ifdef DEBUG_TREE
1.134 veillard 4758: xmlGenericError(xmlGenericErrorContext,
4759: "xmlDtdDump : no internal subset\n");
1.86 daniel 4760: #endif
1.17 daniel 4761: return;
4762: }
1.38 daniel 4763: xmlBufferWriteChar(buf, "<!DOCTYPE ");
1.92 daniel 4764: xmlBufferWriteCHAR(buf, dtd->name);
4765: if (dtd->ExternalID != NULL) {
1.43 daniel 4766: xmlBufferWriteChar(buf, " PUBLIC ");
1.92 daniel 4767: xmlBufferWriteQuotedString(buf, dtd->ExternalID);
1.43 daniel 4768: xmlBufferWriteChar(buf, " ");
1.92 daniel 4769: xmlBufferWriteQuotedString(buf, dtd->SystemID);
4770: } else if (dtd->SystemID != NULL) {
1.43 daniel 4771: xmlBufferWriteChar(buf, " SYSTEM ");
1.92 daniel 4772: xmlBufferWriteQuotedString(buf, dtd->SystemID);
1.17 daniel 4773: }
1.92 daniel 4774: if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4775: (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4776: xmlBufferWriteChar(buf, ">");
1.21 daniel 4777: return;
4778: }
1.38 daniel 4779: xmlBufferWriteChar(buf, " [\n");
1.99 daniel 4780: xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4781: #if 0
1.92 daniel 4782: if (dtd->entities != NULL)
4783: xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4784: if (dtd->notations != NULL)
4785: xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4786: if (dtd->elements != NULL)
4787: xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4788: if (dtd->attributes != NULL)
4789: xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
1.99 daniel 4790: #endif
4791: xmlBufferWriteChar(buf, "]>");
1.17 daniel 4792: }
4793:
1.23 daniel 4794: /**
4795: * xmlAttrDump:
1.42 daniel 4796: * @buf: the XML buffer output
1.23 daniel 4797: * @doc: the document
4798: * @cur: the attribute pointer
4799: *
4800: * Dump an XML attribute
1.1 veillard 4801: */
1.28 daniel 4802: static void
1.38 daniel 4803: xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
1.61 daniel 4804: xmlChar *value;
1.1 veillard 4805:
4806: if (cur == NULL) {
1.86 daniel 4807: #ifdef DEBUG_TREE
1.134 veillard 4808: xmlGenericError(xmlGenericErrorContext,
4809: "xmlAttrDump : property == NULL\n");
1.86 daniel 4810: #endif
1.1 veillard 4811: return;
4812: }
1.38 daniel 4813: xmlBufferWriteChar(buf, " ");
1.56 daniel 4814: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4815: xmlBufferWriteCHAR(buf, cur->ns->prefix);
4816: xmlBufferWriteChar(buf, ":");
4817: }
1.38 daniel 4818: xmlBufferWriteCHAR(buf, cur->name);
1.90 daniel 4819: value = xmlNodeListGetString(doc, cur->children, 0);
1.149 ! veillard 4820: if (value != NULL) {
1.43 daniel 4821: xmlBufferWriteChar(buf, "=");
4822: xmlBufferWriteQuotedString(buf, value);
1.57 daniel 4823: xmlFree(value);
1.34 daniel 4824: } else {
1.38 daniel 4825: xmlBufferWriteChar(buf, "=\"\"");
1.3 veillard 4826: }
1.8 veillard 4827: }
4828:
1.23 daniel 4829: /**
4830: * xmlAttrListDump:
1.42 daniel 4831: * @buf: the XML buffer output
1.23 daniel 4832: * @doc: the document
4833: * @cur: the first attribute pointer
4834: *
4835: * Dump a list of XML attributes
1.8 veillard 4836: */
1.28 daniel 4837: static void
1.38 daniel 4838: xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
1.8 veillard 4839: if (cur == NULL) {
1.86 daniel 4840: #ifdef DEBUG_TREE
1.134 veillard 4841: xmlGenericError(xmlGenericErrorContext,
4842: "xmlAttrListDump : property == NULL\n");
1.86 daniel 4843: #endif
1.1 veillard 4844: return;
4845: }
1.8 veillard 4846: while (cur != NULL) {
1.38 daniel 4847: xmlAttrDump(buf, doc, cur);
1.8 veillard 4848: cur = cur->next;
1.1 veillard 4849: }
4850: }
4851:
4852:
1.82 daniel 4853:
1.23 daniel 4854: /**
4855: * xmlNodeListDump:
1.42 daniel 4856: * @buf: the XML buffer output
1.23 daniel 4857: * @doc: the document
4858: * @cur: the first node
4859: * @level: the imbrication level for indenting
1.64 daniel 4860: * @format: is formatting allowed
1.23 daniel 4861: *
4862: * Dump an XML node list, recursive behaviour,children are printed too.
4863: */
1.28 daniel 4864: static void
1.64 daniel 4865: xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4866: int format) {
4867: int i;
1.25 daniel 4868:
1.1 veillard 4869: if (cur == NULL) {
1.86 daniel 4870: #ifdef DEBUG_TREE
1.134 veillard 4871: xmlGenericError(xmlGenericErrorContext,
4872: "xmlNodeListDump : node == NULL\n");
1.86 daniel 4873: #endif
1.1 veillard 4874: return;
4875: }
1.8 veillard 4876: while (cur != NULL) {
1.64 daniel 4877: if ((format) && (xmlIndentTreeOutput) &&
4878: (cur->type == XML_ELEMENT_NODE))
4879: for (i = 0;i < level;i++)
4880: xmlBufferWriteChar(buf, " ");
4881: xmlNodeDump(buf, doc, cur, level, format);
4882: if (format) {
4883: xmlBufferWriteChar(buf, "\n");
1.25 daniel 4884: }
1.8 veillard 4885: cur = cur->next;
1.3 veillard 4886: }
1.1 veillard 4887: }
4888:
1.23 daniel 4889: /**
1.25 daniel 4890: * xmlNodeDump:
1.42 daniel 4891: * @buf: the XML buffer output
1.23 daniel 4892: * @doc: the document
4893: * @cur: the current node
4894: * @level: the imbrication level for indenting
1.64 daniel 4895: * @format: is formatting allowed
1.23 daniel 4896: *
4897: * Dump an XML node, recursive behaviour,children are printed too.
1.1 veillard 4898: */
1.125 veillard 4899: void
1.64 daniel 4900: xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4901: int format) {
1.8 veillard 4902: int i;
1.64 daniel 4903: xmlNodePtr tmp;
1.8 veillard 4904:
1.1 veillard 4905: if (cur == NULL) {
1.86 daniel 4906: #ifdef DEBUG_TREE
1.134 veillard 4907: xmlGenericError(xmlGenericErrorContext,
4908: "xmlNodeDump : node == NULL\n");
1.86 daniel 4909: #endif
1.8 veillard 4910: return;
4911: }
1.141 veillard 4912: if (cur->type == XML_XINCLUDE_START)
4913: return;
4914: if (cur->type == XML_XINCLUDE_END)
4915: return;
1.92 daniel 4916: if (cur->type == XML_DTD_NODE) {
4917: xmlDtdDump(buf, (xmlDtdPtr) cur);
4918: return;
4919: }
1.99 daniel 4920: if (cur->type == XML_ELEMENT_DECL) {
4921: xmlDumpElementDecl(buf, (xmlElementPtr) cur);
4922: return;
4923: }
4924: if (cur->type == XML_ATTRIBUTE_DECL) {
4925: xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
4926: return;
4927: }
4928: if (cur->type == XML_ENTITY_DECL) {
4929: xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
4930: return;
4931: }
1.23 daniel 4932: if (cur->type == XML_TEXT_NODE) {
1.45 daniel 4933: if (cur->content != NULL) {
1.61 daniel 4934: xmlChar *buffer;
1.45 daniel 4935:
1.70 daniel 4936: #ifndef XML_USE_BUFFER_CONTENT
1.46 daniel 4937: buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
1.70 daniel 4938: #else
4939: buffer = xmlEncodeEntitiesReentrant(doc,
4940: xmlBufferContent(cur->content));
4941: #endif
1.45 daniel 4942: if (buffer != NULL) {
4943: xmlBufferWriteCHAR(buf, buffer);
1.57 daniel 4944: xmlFree(buffer);
1.45 daniel 4945: }
4946: }
1.14 daniel 4947: return;
4948: }
1.52 daniel 4949: if (cur->type == XML_PI_NODE) {
4950: if (cur->content != NULL) {
4951: xmlBufferWriteChar(buf, "<?");
4952: xmlBufferWriteCHAR(buf, cur->name);
4953: if (cur->content != NULL) {
4954: xmlBufferWriteChar(buf, " ");
1.70 daniel 4955: #ifndef XML_USE_BUFFER_CONTENT
1.52 daniel 4956: xmlBufferWriteCHAR(buf, cur->content);
1.70 daniel 4957: #else
4958: xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4959: #endif
1.52 daniel 4960: }
1.89 daniel 4961: xmlBufferWriteChar(buf, "?>");
4962: } else {
4963: xmlBufferWriteChar(buf, "<?");
4964: xmlBufferWriteCHAR(buf, cur->name);
1.64 daniel 4965: xmlBufferWriteChar(buf, "?>");
1.52 daniel 4966: }
4967: return;
4968: }
1.23 daniel 4969: if (cur->type == XML_COMMENT_NODE) {
1.14 daniel 4970: if (cur->content != NULL) {
1.38 daniel 4971: xmlBufferWriteChar(buf, "<!--");
1.70 daniel 4972: #ifndef XML_USE_BUFFER_CONTENT
1.38 daniel 4973: xmlBufferWriteCHAR(buf, cur->content);
1.70 daniel 4974: #else
4975: xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4976: #endif
1.64 daniel 4977: xmlBufferWriteChar(buf, "-->");
1.14 daniel 4978: }
1.8 veillard 4979: return;
4980: }
1.23 daniel 4981: if (cur->type == XML_ENTITY_REF_NODE) {
1.38 daniel 4982: xmlBufferWriteChar(buf, "&");
4983: xmlBufferWriteCHAR(buf, cur->name);
4984: xmlBufferWriteChar(buf, ";");
1.50 daniel 4985: return;
4986: }
4987: if (cur->type == XML_CDATA_SECTION_NODE) {
4988: xmlBufferWriteChar(buf, "<![CDATA[");
4989: if (cur->content != NULL)
1.70 daniel 4990: #ifndef XML_USE_BUFFER_CONTENT
1.50 daniel 4991: xmlBufferWriteCHAR(buf, cur->content);
1.70 daniel 4992: #else
4993: xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4994: #endif
1.50 daniel 4995: xmlBufferWriteChar(buf, "]]>");
1.23 daniel 4996: return;
4997: }
1.8 veillard 4998:
1.64 daniel 4999: if (format == 1) {
1.91 daniel 5000: tmp = cur->children;
1.64 daniel 5001: while (tmp != NULL) {
5002: if ((tmp->type == XML_TEXT_NODE) ||
5003: (tmp->type == XML_ENTITY_REF_NODE)) {
5004: format = 0;
5005: break;
5006: }
5007: tmp = tmp->next;
5008: }
5009: }
1.38 daniel 5010: xmlBufferWriteChar(buf, "<");
1.16 daniel 5011: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1.38 daniel 5012: xmlBufferWriteCHAR(buf, cur->ns->prefix);
5013: xmlBufferWriteChar(buf, ":");
1.8 veillard 5014: }
5015:
1.38 daniel 5016: xmlBufferWriteCHAR(buf, cur->name);
1.19 daniel 5017: if (cur->nsDef)
1.38 daniel 5018: xmlNsListDump(buf, cur->nsDef);
1.8 veillard 5019: if (cur->properties != NULL)
1.38 daniel 5020: xmlAttrListDump(buf, doc, cur->properties);
1.8 veillard 5021:
1.90 daniel 5022: if ((cur->content == NULL) && (cur->children == NULL) &&
1.87 daniel 5023: (!xmlSaveNoEmptyTags)) {
1.64 daniel 5024: xmlBufferWriteChar(buf, "/>");
1.1 veillard 5025: return;
5026: }
1.38 daniel 5027: xmlBufferWriteChar(buf, ">");
1.46 daniel 5028: if (cur->content != NULL) {
1.61 daniel 5029: xmlChar *buffer;
1.46 daniel 5030:
1.70 daniel 5031: #ifndef XML_USE_BUFFER_CONTENT
1.46 daniel 5032: buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
1.70 daniel 5033: #else
5034: buffer = xmlEncodeEntitiesReentrant(doc,
5035: xmlBufferContent(cur->content));
5036: #endif
1.46 daniel 5037: if (buffer != NULL) {
5038: xmlBufferWriteCHAR(buf, buffer);
1.57 daniel 5039: xmlFree(buffer);
1.46 daniel 5040: }
5041: }
1.90 daniel 5042: if (cur->children != NULL) {
1.64 daniel 5043: if (format) xmlBufferWriteChar(buf, "\n");
1.99 daniel 5044: xmlNodeListDump(buf, doc, cur->children,
5045: (level >= 0?level+1:-1), format);
1.64 daniel 5046: if ((xmlIndentTreeOutput) && (format))
5047: for (i = 0;i < level;i++)
5048: xmlBufferWriteChar(buf, " ");
1.8 veillard 5049: }
1.38 daniel 5050: xmlBufferWriteChar(buf, "</");
1.16 daniel 5051: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1.38 daniel 5052: xmlBufferWriteCHAR(buf, cur->ns->prefix);
5053: xmlBufferWriteChar(buf, ":");
1.1 veillard 5054: }
1.8 veillard 5055:
1.38 daniel 5056: xmlBufferWriteCHAR(buf, cur->name);
1.64 daniel 5057: xmlBufferWriteChar(buf, ">");
1.1 veillard 5058: }
5059:
1.23 daniel 5060: /**
1.82 daniel 5061: * xmlElemDump:
1.104 daniel 5062: * @f: the FILE * for the output
1.82 daniel 5063: * @doc: the document
5064: * @cur: the current node
5065: *
5066: * Dump an XML/HTML node, recursive behaviour,children are printed too.
5067: */
5068: void
5069: xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5070: xmlBufferPtr buf;
5071:
5072: if (cur == NULL) {
5073: #ifdef DEBUG_TREE
1.134 veillard 5074: xmlGenericError(xmlGenericErrorContext,
5075: "xmlElemDump : cur == NULL\n");
1.82 daniel 5076: #endif
5077: return;
5078: }
5079: if (doc == NULL) {
5080: #ifdef DEBUG_TREE
1.134 veillard 5081: xmlGenericError(xmlGenericErrorContext,
5082: "xmlElemDump : doc == NULL\n");
1.82 daniel 5083: #endif
5084: }
5085: buf = xmlBufferCreate();
5086: if (buf == NULL) return;
5087: if ((doc != NULL) &&
5088: (doc->type == XML_HTML_DOCUMENT_NODE)) {
1.101 daniel 5089: #ifdef LIBXML_HTML_ENABLED
1.82 daniel 5090: htmlNodeDump(buf, doc, cur);
1.101 daniel 5091: #else
1.134 veillard 5092: xmlGenericError(xmlGenericErrorContext,
5093: "HTML support not compiled in\n");
1.101 daniel 5094: #endif /* LIBXML_HTML_ENABLED */
1.82 daniel 5095: } else
5096: xmlNodeDump(buf, doc, cur, 0, 1);
5097: xmlBufferDump(f, buf);
5098: xmlBufferFree(buf);
5099: }
5100:
1.106 daniel 5101: /************************************************************************
5102: * *
5103: * Dumping XML tree content to an I/O output buffer *
5104: * *
5105: ************************************************************************/
5106:
1.125 veillard 5107: void
1.106 daniel 5108: xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
1.108 daniel 5109: int level, int format, const char *encoding);
1.106 daniel 5110: static void
5111: xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
1.108 daniel 5112: int level, int format, const char *encoding);
1.106 daniel 5113: /**
5114: * xmlNsDumpOutput:
5115: * @buf: the XML buffer output
5116: * @cur: a namespace
5117: *
5118: * Dump a local Namespace definition.
5119: * Should be called in the context of attributes dumps.
5120: */
5121: static void
5122: xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5123: if (cur == NULL) {
5124: #ifdef DEBUG_TREE
1.134 veillard 5125: xmlGenericError(xmlGenericErrorContext,
5126: "xmlNsDump : Ns == NULL\n");
1.106 daniel 5127: #endif
5128: return;
5129: }
1.120 veillard 5130: if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
1.106 daniel 5131: /* Within the context of an element attributes */
5132: if (cur->prefix != NULL) {
5133: xmlOutputBufferWriteString(buf, " xmlns:");
5134: xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5135: } else
5136: xmlOutputBufferWriteString(buf, " xmlns");
5137: xmlOutputBufferWriteString(buf, "=");
5138: xmlBufferWriteQuotedString(buf->buffer, cur->href);
5139: }
5140: }
5141:
5142: /**
5143: * xmlNsListDumpOutput:
5144: * @buf: the XML buffer output
5145: * @cur: the first namespace
5146: *
5147: * Dump a list of local Namespace definitions.
5148: * Should be called in the context of attributes dumps.
5149: */
5150: static void
5151: xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5152: while (cur != NULL) {
5153: xmlNsDumpOutput(buf, cur);
5154: cur = cur->next;
5155: }
5156: }
5157:
5158: /**
5159: * xmlDtdDumpOutput:
5160: * @buf: the XML buffer output
5161: * @doc: the document
1.108 daniel 5162: * @encoding: an optional encoding string
1.106 daniel 5163: *
5164: * Dump the XML document DTD, if any.
5165: */
5166: static void
1.108 daniel 5167: xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
1.106 daniel 5168: if (dtd == NULL) {
5169: #ifdef DEBUG_TREE
1.134 veillard 5170: xmlGenericError(xmlGenericErrorContext,
5171: "xmlDtdDump : no internal subset\n");
1.106 daniel 5172: #endif
5173: return;
5174: }
5175: xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5176: xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5177: if (dtd->ExternalID != NULL) {
5178: xmlOutputBufferWriteString(buf, " PUBLIC ");
5179: xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5180: xmlOutputBufferWriteString(buf, " ");
5181: xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5182: } else if (dtd->SystemID != NULL) {
5183: xmlOutputBufferWriteString(buf, " SYSTEM ");
5184: xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5185: }
5186: if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5187: (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5188: xmlOutputBufferWriteString(buf, ">");
5189: return;
5190: }
5191: xmlOutputBufferWriteString(buf, " [\n");
1.108 daniel 5192: xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
1.106 daniel 5193: xmlOutputBufferWriteString(buf, "]>");
5194: }
5195:
5196: /**
5197: * xmlAttrDumpOutput:
5198: * @buf: the XML buffer output
5199: * @doc: the document
5200: * @cur: the attribute pointer
1.108 daniel 5201: * @encoding: an optional encoding string
1.106 daniel 5202: *
5203: * Dump an XML attribute
5204: */
5205: static void
1.108 daniel 5206: xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5207: const char *encoding) {
1.106 daniel 5208: xmlChar *value;
5209:
5210: if (cur == NULL) {
5211: #ifdef DEBUG_TREE
1.134 veillard 5212: xmlGenericError(xmlGenericErrorContext,
5213: "xmlAttrDump : property == NULL\n");
1.106 daniel 5214: #endif
5215: return;
5216: }
5217: xmlOutputBufferWriteString(buf, " ");
5218: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5219: xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5220: xmlOutputBufferWriteString(buf, ":");
5221: }
5222: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5223: value = xmlNodeListGetString(doc, cur->children, 0);
5224: if (value) {
5225: xmlOutputBufferWriteString(buf, "=");
5226: xmlBufferWriteQuotedString(buf->buffer, value);
5227: xmlFree(value);
5228: } else {
5229: xmlOutputBufferWriteString(buf, "=\"\"");
5230: }
5231: }
5232:
5233: /**
5234: * xmlAttrListDumpOutput:
5235: * @buf: the XML buffer output
5236: * @doc: the document
5237: * @cur: the first attribute pointer
1.108 daniel 5238: * @encoding: an optional encoding string
1.106 daniel 5239: *
5240: * Dump a list of XML attributes
5241: */
5242: static void
1.108 daniel 5243: xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5244: xmlAttrPtr cur, const char *encoding) {
1.106 daniel 5245: if (cur == NULL) {
5246: #ifdef DEBUG_TREE
1.134 veillard 5247: xmlGenericError(xmlGenericErrorContext,
5248: "xmlAttrListDump : property == NULL\n");
1.106 daniel 5249: #endif
5250: return;
5251: }
5252: while (cur != NULL) {
1.108 daniel 5253: xmlAttrDumpOutput(buf, doc, cur, encoding);
1.106 daniel 5254: cur = cur->next;
5255: }
5256: }
5257:
5258:
5259:
5260: /**
5261: * xmlNodeListDumpOutput:
5262: * @buf: the XML buffer output
5263: * @doc: the document
5264: * @cur: the first node
5265: * @level: the imbrication level for indenting
5266: * @format: is formatting allowed
1.108 daniel 5267: * @encoding: an optional encoding string
1.106 daniel 5268: *
5269: * Dump an XML node list, recursive behaviour,children are printed too.
5270: */
5271: static void
5272: xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
1.108 daniel 5273: xmlNodePtr cur, int level, int format, const char *encoding) {
1.106 daniel 5274: int i;
5275:
5276: if (cur == NULL) {
5277: #ifdef DEBUG_TREE
1.134 veillard 5278: xmlGenericError(xmlGenericErrorContext,
5279: "xmlNodeListDump : node == NULL\n");
1.106 daniel 5280: #endif
5281: return;
5282: }
5283: while (cur != NULL) {
5284: if ((format) && (xmlIndentTreeOutput) &&
5285: (cur->type == XML_ELEMENT_NODE))
5286: for (i = 0;i < level;i++)
5287: xmlOutputBufferWriteString(buf, " ");
1.108 daniel 5288: xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
1.106 daniel 5289: if (format) {
5290: xmlOutputBufferWriteString(buf, "\n");
5291: }
5292: cur = cur->next;
5293: }
5294: }
5295:
5296: /**
5297: * xmlNodeDumpOutput:
5298: * @buf: the XML buffer output
5299: * @doc: the document
5300: * @cur: the current node
5301: * @level: the imbrication level for indenting
5302: * @format: is formatting allowed
1.108 daniel 5303: * @encoding: an optional encoding string
1.106 daniel 5304: *
5305: * Dump an XML node, recursive behaviour,children are printed too.
5306: */
1.125 veillard 5307: void
1.106 daniel 5308: xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
1.108 daniel 5309: int level, int format, const char *encoding) {
1.106 daniel 5310: int i;
5311: xmlNodePtr tmp;
5312:
5313: if (cur == NULL) {
5314: #ifdef DEBUG_TREE
1.134 veillard 5315: xmlGenericError(xmlGenericErrorContext,
5316: "xmlNodeDump : node == NULL\n");
1.106 daniel 5317: #endif
5318: return;
5319: }
1.141 veillard 5320: if (cur->type == XML_XINCLUDE_START)
5321: return;
5322: if (cur->type == XML_XINCLUDE_END)
5323: return;
1.106 daniel 5324: if (cur->type == XML_DTD_NODE) {
1.108 daniel 5325: xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
1.106 daniel 5326: return;
5327: }
5328: if (cur->type == XML_ELEMENT_DECL) {
5329: xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5330: return;
5331: }
5332: if (cur->type == XML_ATTRIBUTE_DECL) {
5333: xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5334: return;
5335: }
5336: if (cur->type == XML_ENTITY_DECL) {
5337: xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5338: return;
5339: }
5340: if (cur->type == XML_TEXT_NODE) {
5341: if (cur->content != NULL) {
5342: xmlChar *buffer;
5343:
5344: #ifndef XML_USE_BUFFER_CONTENT
1.108 daniel 5345: if (encoding == NULL)
5346: buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5347: else
5348: buffer = xmlEncodeSpecialChars(doc, cur->content);
1.106 daniel 5349: #else
1.108 daniel 5350: if (encoding == NULL)
5351: buffer = xmlEncodeEntitiesReentrant(doc,
5352: xmlBufferContent(cur->content));
5353: else
5354: buffer = xmlEncodeSpecialChars(doc,
5355: xmlBufferContent(cur->content));
1.106 daniel 5356: #endif
5357: if (buffer != NULL) {
5358: xmlOutputBufferWriteString(buf, (const char *)buffer);
5359: xmlFree(buffer);
5360: }
5361: }
5362: return;
5363: }
5364: if (cur->type == XML_PI_NODE) {
5365: if (cur->content != NULL) {
5366: xmlOutputBufferWriteString(buf, "<?");
5367: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5368: if (cur->content != NULL) {
5369: xmlOutputBufferWriteString(buf, " ");
5370: #ifndef XML_USE_BUFFER_CONTENT
5371: xmlOutputBufferWriteString(buf, (const char *)cur->content);
5372: #else
5373: xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5374: #endif
5375: }
5376: xmlOutputBufferWriteString(buf, "?>");
5377: } else {
5378: xmlOutputBufferWriteString(buf, "<?");
5379: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5380: xmlOutputBufferWriteString(buf, "?>");
5381: }
5382: return;
5383: }
5384: if (cur->type == XML_COMMENT_NODE) {
5385: if (cur->content != NULL) {
5386: xmlOutputBufferWriteString(buf, "<!--");
5387: #ifndef XML_USE_BUFFER_CONTENT
5388: xmlOutputBufferWriteString(buf, (const char *)cur->content);
5389: #else
5390: xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5391: #endif
5392: xmlOutputBufferWriteString(buf, "-->");
5393: }
5394: return;
5395: }
5396: if (cur->type == XML_ENTITY_REF_NODE) {
5397: xmlOutputBufferWriteString(buf, "&");
5398: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5399: xmlOutputBufferWriteString(buf, ";");
5400: return;
5401: }
5402: if (cur->type == XML_CDATA_SECTION_NODE) {
5403: xmlOutputBufferWriteString(buf, "<![CDATA[");
5404: if (cur->content != NULL)
5405: #ifndef XML_USE_BUFFER_CONTENT
5406: xmlOutputBufferWriteString(buf, (const char *)cur->content);
5407: #else
5408: xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5409: #endif
5410: xmlOutputBufferWriteString(buf, "]]>");
5411: return;
5412: }
5413:
5414: if (format == 1) {
5415: tmp = cur->children;
5416: while (tmp != NULL) {
5417: if ((tmp->type == XML_TEXT_NODE) ||
5418: (tmp->type == XML_ENTITY_REF_NODE)) {
5419: format = 0;
5420: break;
5421: }
5422: tmp = tmp->next;
5423: }
5424: }
5425: xmlOutputBufferWriteString(buf, "<");
5426: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5427: xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5428: xmlOutputBufferWriteString(buf, ":");
5429: }
5430:
5431: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5432: if (cur->nsDef)
5433: xmlNsListDumpOutput(buf, cur->nsDef);
5434: if (cur->properties != NULL)
1.108 daniel 5435: xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
1.106 daniel 5436:
5437: if ((cur->content == NULL) && (cur->children == NULL) &&
5438: (!xmlSaveNoEmptyTags)) {
5439: xmlOutputBufferWriteString(buf, "/>");
5440: return;
5441: }
5442: xmlOutputBufferWriteString(buf, ">");
5443: if (cur->content != NULL) {
5444: xmlChar *buffer;
5445:
5446: #ifndef XML_USE_BUFFER_CONTENT
1.108 daniel 5447: if (encoding == NULL)
5448: buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5449: else
5450: buffer = xmlEncodeSpecialChars(doc, cur->content);
1.106 daniel 5451: #else
1.108 daniel 5452: if (encoding == NULL)
5453: buffer = xmlEncodeEntitiesReentrant(doc,
5454: xmlBufferContent(cur->content));
5455: else
5456: buffer = xmlEncodeSpecialChars(doc,
5457: xmlBufferContent(cur->content));
1.106 daniel 5458: #endif
5459: if (buffer != NULL) {
5460: xmlOutputBufferWriteString(buf, (const char *)buffer);
5461: xmlFree(buffer);
5462: }
5463: }
5464: if (cur->children != NULL) {
5465: if (format) xmlOutputBufferWriteString(buf, "\n");
5466: xmlNodeListDumpOutput(buf, doc, cur->children,
1.108 daniel 5467: (level >= 0?level+1:-1), format, encoding);
1.106 daniel 5468: if ((xmlIndentTreeOutput) && (format))
5469: for (i = 0;i < level;i++)
5470: xmlOutputBufferWriteString(buf, " ");
5471: }
5472: xmlOutputBufferWriteString(buf, "</");
5473: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5474: xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5475: xmlOutputBufferWriteString(buf, ":");
5476: }
5477:
5478: xmlOutputBufferWriteString(buf, (const char *)cur->name);
5479: xmlOutputBufferWriteString(buf, ">");
5480: }
5481:
5482: /**
5483: * xmlDocContentDumpOutput:
5484: * @buf: the XML buffer output
5485: * @cur: the document
1.107 daniel 5486: * @encoding: an optional encoding string
1.146 veillard 5487: * @format: should formatting spaces been added
1.106 daniel 5488: *
5489: * Dump an XML document.
5490: */
5491: static void
1.107 daniel 5492: xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
1.146 veillard 5493: const char *encoding, int format) {
1.106 daniel 5494: xmlOutputBufferWriteString(buf, "<?xml version=");
5495: if (cur->version != NULL)
5496: xmlBufferWriteQuotedString(buf->buffer, cur->version);
5497: else
5498: xmlOutputBufferWriteString(buf, "\"1.0\"");
1.109 daniel 5499: if (encoding == NULL) {
5500: if (cur->encoding != NULL)
5501: encoding = (const char *) cur->encoding;
5502: else if (cur->charset != XML_CHAR_ENCODING_UTF8)
1.112 veillard 5503: encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
1.109 daniel 5504: }
1.107 daniel 5505: if (encoding != NULL) {
1.106 daniel 5506: xmlOutputBufferWriteString(buf, " encoding=");
1.107 daniel 5507: xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
1.106 daniel 5508: }
5509: switch (cur->standalone) {
5510: case 0:
5511: xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5512: break;
5513: case 1:
5514: xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5515: break;
5516: }
5517: xmlOutputBufferWriteString(buf, "?>\n");
5518: if (cur->children != NULL) {
5519: xmlNodePtr child = cur->children;
5520:
5521: while (child != NULL) {
1.146 veillard 5522: xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
1.106 daniel 5523: xmlOutputBufferWriteString(buf, "\n");
5524: child = child->next;
5525: }
5526: }
5527: }
5528:
5529: /************************************************************************
5530: * *
5531: * Saving functions front-ends *
5532: * *
5533: ************************************************************************/
5534:
1.23 daniel 5535: /**
1.144 veillard 5536: * xmlDocDumpMemoryEnc:
5537: * @out_doc: Document to generate XML text from
5538: * @doc_txt_ptr: Memory pointer for allocated XML text
5539: * @doc_txt_len: Length of the generated XML text
5540: * @txt_encoding: Character encoding to use when generating XML text
1.146 veillard 5541: * @format: should formatting spaces been added
1.144 veillard 5542: *
5543: * Dump the current DOM tree into memory using the character encoding specified
5544: * by the caller. Note it is up to the caller of this function to free the
5545: * allocated memory.
5546: */
5547:
5548: void
1.146 veillard 5549: xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5550: int * doc_txt_len, const char * txt_encoding, int format) {
1.144 veillard 5551: int dummy = 0;
5552:
5553: xmlCharEncoding doc_charset;
5554: xmlOutputBufferPtr out_buff = NULL;
5555: xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5556:
5557: if (doc_txt_len == NULL) {
5558: doc_txt_len = &dummy; /* Continue, caller just won't get length */
5559: }
5560:
5561: if (doc_txt_ptr == NULL) {
5562: *doc_txt_len = 0;
5563: xmlGenericError(xmlGenericErrorContext,
1.146 veillard 5564: "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
1.144 veillard 5565: return;
5566: }
5567:
5568: *doc_txt_ptr = NULL;
5569: *doc_txt_len = 0;
5570:
5571: if (out_doc == NULL) {
5572: /* No document, no output */
5573: xmlGenericError(xmlGenericErrorContext,
1.146 veillard 5574: "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
1.144 veillard 5575: return;
5576: }
5577:
5578: /*
5579: * Validate the encoding value, if provided.
5580: * This logic is copied from xmlSaveFileEnc.
5581: */
5582:
1.147 veillard 5583: if (txt_encoding == NULL)
5584: txt_encoding = (const char *) out_doc->encoding;
1.144 veillard 5585: if (txt_encoding != NULL) {
5586: doc_charset = xmlParseCharEncoding(txt_encoding);
5587:
5588: if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5589: xmlGenericError(xmlGenericErrorContext,
1.146 veillard 5590: "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
1.144 veillard 5591: return;
5592:
5593: } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5594: conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5595: if ( conv_hdlr == NULL ) {
5596: xmlGenericError(xmlGenericErrorContext,
5597: "%s: %s %s '%s'\n",
1.146 veillard 5598: "xmlDocDumpFormatMemoryEnc",
1.144 veillard 5599: "Failed to identify encoding handler for",
5600: "character set",
5601: txt_encoding);
5602: return;
5603: }
5604: }
5605: }
5606:
5607: if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5608: xmlGenericError(xmlGenericErrorContext,
1.146 veillard 5609: "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
1.144 veillard 5610: return;
5611: }
5612:
1.146 veillard 5613: xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
1.147 veillard 5614: xmlOutputBufferFlush(out_buff);
5615: if (out_buff->conv != NULL) {
5616: *doc_txt_len = out_buff->conv->use;
5617: *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5618: } else {
5619: *doc_txt_len = out_buff->buffer->use;
5620: *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5621: }
1.144 veillard 5622: (void)xmlOutputBufferClose(out_buff);
5623:
5624: if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5625: *doc_txt_len = 0;
5626: xmlGenericError(xmlGenericErrorContext,
1.146 veillard 5627: "xmlDocDumpFormatMemoryEnc: %s\n",
1.144 veillard 5628: "Failed to allocate memory for document text representation.");
5629: }
5630:
5631: return;
1.147 veillard 5632: }
5633:
5634: /**
5635: * xmlDocDumpMemory:
5636: * @cur: the document
5637: * @mem: OUT: the memory pointer
5638: * @size: OUT: the memory lenght
5639: *
5640: * Dump an XML document in memory and return the xmlChar * and it's size.
5641: * It's up to the caller to free the memory.
5642: */
5643: void
5644: xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
5645: xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5646: }
5647:
5648: /**
5649: * xmlDocDumpFormatMemory:
5650: * @cur: the document
5651: * @mem: OUT: the memory pointer
5652: * @size: OUT: the memory lenght
5653: * @format: should formatting spaces been added
5654: *
5655: *
5656: * Dump an XML document in memory and return the xmlChar * and it's size.
5657: * It's up to the caller to free the memory.
5658: */
5659: void
5660: xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5661: xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
1.144 veillard 5662: }
5663:
5664: /**
1.146 veillard 5665: * xmlDocDumpMemoryEnc:
5666: * @out_doc: Document to generate XML text from
5667: * @doc_txt_ptr: Memory pointer for allocated XML text
5668: * @doc_txt_len: Length of the generated XML text
5669: * @txt_encoding: Character encoding to use when generating XML text
5670: *
5671: * Dump the current DOM tree into memory using the character encoding specified
5672: * by the caller. Note it is up to the caller of this function to free the
5673: * allocated memory.
5674: */
5675:
5676: void
5677: xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5678: int * doc_txt_len, const char * txt_encoding) {
5679: xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5680: txt_encoding, 1);
5681: }
5682:
5683: /**
1.23 daniel 5684: * xmlGetDocCompressMode:
5685: * @doc: the document
5686: *
5687: * get the compression ratio for a document, ZLIB based
1.36 daniel 5688: * Returns 0 (uncompressed) to 9 (max compression)
1.23 daniel 5689: */
1.28 daniel 5690: int
1.82 daniel 5691: xmlGetDocCompressMode (xmlDocPtr doc) {
1.23 daniel 5692: if (doc == NULL) return(-1);
5693: return(doc->compression);
5694: }
5695:
5696: /**
5697: * xmlSetDocCompressMode:
5698: * @doc: the document
5699: * @mode: the compression ratio
5700: *
5701: * set the compression ratio for a document, ZLIB based
5702: * Correct values: 0 (uncompressed) to 9 (max compression)
5703: */
1.28 daniel 5704: void
5705: xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1.23 daniel 5706: if (doc == NULL) return;
5707: if (mode < 0) doc->compression = 0;
5708: else if (mode > 9) doc->compression = 9;
5709: else doc->compression = mode;
5710: }
5711:
5712: /**
5713: * xmlGetCompressMode:
5714: *
5715: * get the default compression mode used, ZLIB based.
1.36 daniel 5716: * Returns 0 (uncompressed) to 9 (max compression)
1.23 daniel 5717: */
1.28 daniel 5718: int
5719: xmlGetCompressMode(void) {
1.23 daniel 5720: return(xmlCompressMode);
5721: }
5722:
5723: /**
5724: * xmlSetCompressMode:
5725: * @mode: the compression ratio
5726: *
5727: * set the default compression mode used, ZLIB based
5728: * Correct values: 0 (uncompressed) to 9 (max compression)
1.1 veillard 5729: */
1.28 daniel 5730: void
5731: xmlSetCompressMode(int mode) {
1.23 daniel 5732: if (mode < 0) xmlCompressMode = 0;
5733: else if (mode > 9) xmlCompressMode = 9;
5734: else xmlCompressMode = mode;
5735: }
1.1 veillard 5736:
1.106 daniel 5737: /**
5738: * xmlDocDump:
5739: * @f: the FILE*
5740: * @cur: the document
5741: *
5742: * Dump an XML document to an open FILE.
5743: *
1.111 veillard 5744: * returns: the number of byte written or -1 in case of failure.
1.106 daniel 5745: */
5746: int
5747: xmlDocDump(FILE *f, xmlDocPtr cur) {
5748: xmlOutputBufferPtr buf;
1.114 veillard 5749: const char * encoding;
5750: xmlCharEncodingHandlerPtr handler = NULL;
1.106 daniel 5751: int ret;
5752:
5753: if (cur == NULL) {
5754: #ifdef DEBUG_TREE
1.134 veillard 5755: xmlGenericError(xmlGenericErrorContext,
5756: "xmlDocDump : document == NULL\n");
1.106 daniel 5757: #endif
5758: return(-1);
5759: }
1.114 veillard 5760: encoding = (const char *) cur->encoding;
1.106 daniel 5761:
1.114 veillard 5762: if (encoding != NULL) {
5763: xmlCharEncoding enc;
1.106 daniel 5764:
1.114 veillard 5765: enc = xmlParseCharEncoding(encoding);
1.106 daniel 5766:
1.114 veillard 5767: if (cur->charset != XML_CHAR_ENCODING_UTF8) {
1.134 veillard 5768: xmlGenericError(xmlGenericErrorContext,
5769: "xmlDocDump: document not in UTF8\n");
1.114 veillard 5770: return(-1);
5771: }
1.115 veillard 5772: if (enc != XML_CHAR_ENCODING_UTF8) {
5773: handler = xmlFindCharEncodingHandler(encoding);
5774: if (handler == NULL) {
5775: xmlFree((char *) cur->encoding);
5776: cur->encoding = NULL;
5777: }
1.114 veillard 5778: }
5779: }
5780: buf = xmlOutputBufferCreateFile(f, handler);
5781: if (buf == NULL) return(-1);
1.146 veillard 5782: xmlDocContentDumpOutput(buf, cur, NULL, 1);
1.106 daniel 5783:
5784: ret = xmlOutputBufferClose(buf);
5785: return(ret);
5786: }
1.1 veillard 5787:
1.106 daniel 5788: /**
5789: * xmlSaveFileTo:
5790: * @buf: an output I/O buffer
5791: * @cur: the document
1.107 daniel 5792: * @encoding: the encoding if any assuming the i/O layer handles the trancoding
1.106 daniel 5793: *
5794: * Dump an XML document to an I/O buffer.
5795: *
1.111 veillard 5796: * returns: the number of byte written or -1 in case of failure.
1.106 daniel 5797: */
5798: int
1.107 daniel 5799: xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
1.106 daniel 5800: int ret;
5801:
5802: if (buf == NULL) return(0);
1.146 veillard 5803: xmlDocContentDumpOutput(buf, cur, encoding, 1);
1.106 daniel 5804: ret = xmlOutputBufferClose(buf);
5805: return(ret);
5806: }
5807:
5808: /**
5809: * xmlSaveFileEnc:
5810: * @filename: the filename (or URL)
5811: * @cur: the document
5812: * @encoding: the name of an encoding (or NULL)
5813: *
5814: * Dump an XML document, converting it to the given encoding
5815: *
1.111 veillard 5816: * returns: the number of byte written or -1 in case of failure.
1.106 daniel 5817: */
5818: int
5819: xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5820: xmlOutputBufferPtr buf;
5821: xmlCharEncodingHandlerPtr handler = NULL;
5822: int ret;
5823:
5824: if (encoding != NULL) {
1.110 daniel 5825: xmlCharEncoding enc;
5826:
5827: enc = xmlParseCharEncoding(encoding);
1.114 veillard 5828: if (cur->charset != XML_CHAR_ENCODING_UTF8) {
1.134 veillard 5829: xmlGenericError(xmlGenericErrorContext,
5830: "xmlSaveFileEnc: document not in UTF8\n");
1.114 veillard 5831: return(-1);
5832: }
1.115 veillard 5833: if (enc != XML_CHAR_ENCODING_UTF8) {
5834: handler = xmlFindCharEncodingHandler(encoding);
5835: if (handler == NULL) {
5836: return(-1);
5837: }
1.110 daniel 5838: }
1.106 daniel 5839: }
5840:
5841: /*
5842: * save the content to a temp buffer.
5843: */
5844: buf = xmlOutputBufferCreateFilename(filename, handler, 0);
5845: if (buf == NULL) return(0);
5846:
1.146 veillard 5847: xmlDocContentDumpOutput(buf, cur, encoding, 1);
1.106 daniel 5848:
5849: ret = xmlOutputBufferClose(buf);
5850: return(ret);
5851: }
1.114 veillard 5852:
5853: /**
5854: * xmlSaveFile:
5855: * @filename: the filename (or URL)
5856: * @cur: the document
5857: *
5858: * Dump an XML document to a file. Will use compression if
5859: * compiled in and enabled. If @filename is "-" the stdout file is
5860: * used.
5861: * returns: the number of byte written or -1 in case of failure.
5862: */
5863: int
5864: xmlSaveFile(const char *filename, xmlDocPtr cur) {
5865: xmlOutputBufferPtr buf;
5866: const char *encoding;
5867: xmlCharEncodingHandlerPtr handler = NULL;
5868: int ret;
5869:
5870: if (cur == NULL)
5871: return(-1);
5872: encoding = (const char *) cur->encoding;
5873:
5874: /*
5875: * save the content to a temp buffer.
5876: */
5877: #ifdef HAVE_ZLIB_H
5878: if (cur->compression < 0) cur->compression = xmlCompressMode;
1.106 daniel 5879: #endif
1.114 veillard 5880: if (encoding != NULL) {
5881: xmlCharEncoding enc;
5882:
5883: enc = xmlParseCharEncoding(encoding);
5884:
5885: if (cur->charset != XML_CHAR_ENCODING_UTF8) {
1.134 veillard 5886: xmlGenericError(xmlGenericErrorContext,
5887: "xmlSaveFile: document not in UTF8\n");
1.114 veillard 5888: return(-1);
5889: }
1.115 veillard 5890: if (enc != XML_CHAR_ENCODING_UTF8) {
5891: handler = xmlFindCharEncodingHandler(encoding);
5892: if (handler == NULL) {
5893: xmlFree((char *) cur->encoding);
5894: cur->encoding = NULL;
5895: }
1.114 veillard 5896: }
5897: }
5898:
5899: buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
5900: if (buf == NULL) return(0);
5901:
1.146 veillard 5902: xmlDocContentDumpOutput(buf, cur, NULL, 1);
1.114 veillard 5903:
5904: ret = xmlOutputBufferClose(buf);
5905: return(ret);
5906: }
5907:
Webmaster