Annotation of XML/tree.c, revision 1.34
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: * TODO Cleanup the Dump mechanism.
1.17 daniel 7: *
1.32 daniel 8: * Daniel.Veillard@w3.org
1.1 veillard 9: */
10:
1.23 daniel 11: #include "config.h"
1.1 veillard 12: #include <stdio.h>
13: #include <ctype.h>
1.23 daniel 14: #include <stdlib.h>
1.7 veillard 15: #include <string.h> /* for memset() only ! */
1.1 veillard 16:
1.23 daniel 17: #ifdef HAVE_ZLIB_H
18: #include <zlib.h>
19: #endif
20:
1.1 veillard 21: #include "tree.h"
1.6 veillard 22: #include "entities.h"
1.33 daniel 23: #include "valid.h"
1.1 veillard 24:
1.7 veillard 25: static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
1.12 daniel 26: int oldXMLWDcompatibility = 0;
1.21 daniel 27: int xmlIndentTreeOutput = 1;
1.7 veillard 28:
1.23 daniel 29: static int xmlCompressMode = 0;
30:
1.32 daniel 31: #define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \
32: xmlNodePtr ulccur = (n)->childs; \
33: if (ulccur == NULL) { \
34: (n)->last = NULL; \
35: } else { \
36: while (ulccur->next != NULL) ulccur = ulccur->next; \
37: (n)->last = ulccur; \
1.34 ! daniel 38: }}
1.32 daniel 39:
1.1 veillard 40: /************************************************************************
41: * *
42: * Allocation and deallocation of basic structures *
43: * *
44: ************************************************************************/
45:
1.23 daniel 46: /**
47: * xmlUpgradeOldNs:
48: * @doc: a document pointer
49: *
50: * Upgrade old style Namespaces (PI) and move them to the root of the document.
1.19 daniel 51: */
1.28 daniel 52: void
53: xmlUpgradeOldNs(xmlDocPtr doc) {
1.19 daniel 54: xmlNsPtr cur;
55:
56: if ((doc == NULL) || (doc->oldNs == NULL)) return;
57: if (doc->root == NULL) {
58: fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
59: return;
60: }
61:
62: cur = doc->oldNs;
63: while (cur->next != NULL) {
64: cur->type = XML_LOCAL_NAMESPACE;
65: cur = cur->next;
66: }
67: cur->type = XML_LOCAL_NAMESPACE;
68: cur->next = doc->root->nsDef;
69: doc->root->nsDef = doc->oldNs;
70: doc->oldNs = NULL;
71: }
72:
1.23 daniel 73: /**
74: * xmlNewNs:
75: * @node: the element carrying the namespace
76: * @href: the URI associated
77: * @prefix: the prefix for the namespace
78: *
1.17 daniel 79: * Creation of a new Namespace.
1.23 daniel 80: * return values: returns a new namespace pointer
1.1 veillard 81: */
1.28 daniel 82: xmlNsPtr
83: xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
1.16 daniel 84: xmlNsPtr cur;
1.1 veillard 85:
1.19 daniel 86: if (href == NULL) {
87: fprintf(stderr, "xmlNewNs: href == NULL !\n");
88: return(NULL);
89: }
90:
1.1 veillard 91: /*
92: * Allocate a new DTD and fill the fields.
93: */
1.16 daniel 94: cur = (xmlNsPtr) malloc(sizeof(xmlNs));
1.1 veillard 95: if (cur == NULL) {
1.16 daniel 96: fprintf(stderr, "xmlNewNs : malloc failed\n");
1.1 veillard 97: return(NULL);
98: }
99:
1.19 daniel 100: cur->type = XML_LOCAL_NAMESPACE;
101: if (href != NULL)
102: cur->href = xmlStrdup(href);
103: else
104: cur->href = NULL;
105: if (prefix != NULL)
106: cur->prefix = xmlStrdup(prefix);
107: else
108: cur->prefix = NULL;
109:
110: /*
111: * Add it at the end to preserve parsing order ...
112: */
1.1 veillard 113: cur->next = NULL;
1.19 daniel 114: if (node != NULL) {
115: if (node->nsDef == NULL) {
116: node->nsDef = cur;
117: } else {
118: xmlNsPtr prev = node->nsDef;
119:
120: while (prev->next != NULL) prev = prev->next;
121: prev->next = cur;
122: }
123: }
124:
125: return(cur);
126: }
127:
1.23 daniel 128: /**
129: * xmlNewGlobalNs:
130: * @doc: the document carrying the namespace
131: * @href: the URI associated
132: * @prefix: the prefix for the namespace
133: *
134: * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
135: * return values: returns a new namespace pointer
1.19 daniel 136: */
1.28 daniel 137: xmlNsPtr
138: xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
1.19 daniel 139: xmlNsPtr cur;
140:
141: /*
142: * Allocate a new DTD and fill the fields.
143: */
144: cur = (xmlNsPtr) malloc(sizeof(xmlNs));
145: if (cur == NULL) {
1.31 daniel 146: fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
1.19 daniel 147: return(NULL);
148: }
149:
150: cur->type = XML_GLOBAL_NAMESPACE;
1.1 veillard 151: if (href != NULL)
1.7 veillard 152: cur->href = xmlStrdup(href);
1.1 veillard 153: else
154: cur->href = NULL;
1.16 daniel 155: if (prefix != NULL)
156: cur->prefix = xmlStrdup(prefix);
1.1 veillard 157: else
1.16 daniel 158: cur->prefix = NULL;
1.17 daniel 159:
160: /*
161: * Add it at the end to preserve parsing order ...
162: */
163: cur->next = NULL;
1.1 veillard 164: if (doc != NULL) {
1.19 daniel 165: if (doc->oldNs == NULL) {
166: doc->oldNs = cur;
1.17 daniel 167: } else {
1.19 daniel 168: xmlNsPtr prev = doc->oldNs;
1.17 daniel 169:
170: while (prev->next != NULL) prev = prev->next;
171: prev->next = cur;
172: }
1.1 veillard 173: }
1.3 veillard 174:
1.1 veillard 175: return(cur);
176: }
177:
1.23 daniel 178: /**
179: * xmlSetNs:
180: * @node: a node in the document
181: * @ns: a namespace pointer
182: *
183: * Associate a namespace to a node, a posteriori.
1.19 daniel 184: */
1.28 daniel 185: void
186: xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
1.19 daniel 187: if (node == NULL) {
188: fprintf(stderr, "xmlSetNs: node == NULL\n");
189: return;
190: }
191: node->ns = ns;
192: }
193:
1.23 daniel 194: /**
195: * xmlFreeNs:
196: * @cur: the namespace pointer
197: *
198: * Free up the structures associated to a namespace
1.1 veillard 199: */
1.28 daniel 200: void
201: xmlFreeNs(xmlNsPtr cur) {
1.1 veillard 202: if (cur == NULL) {
1.17 daniel 203: fprintf(stderr, "xmlFreeNs : ns == NULL\n");
1.1 veillard 204: return;
205: }
206: if (cur->href != NULL) free((char *) cur->href);
1.16 daniel 207: if (cur->prefix != NULL) free((char *) cur->prefix);
208: memset(cur, -1, sizeof(xmlNs));
1.1 veillard 209: free(cur);
210: }
211:
1.23 daniel 212: /**
213: * xmlFreeNsList:
214: * @cur: the first namespace pointer
215: *
216: * Free up all the structures associated to the chained namespaces.
1.6 veillard 217: */
1.28 daniel 218: void
219: xmlFreeNsList(xmlNsPtr cur) {
1.16 daniel 220: xmlNsPtr next;
1.6 veillard 221: if (cur == NULL) {
1.16 daniel 222: fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
1.6 veillard 223: return;
224: }
225: while (cur != NULL) {
226: next = cur->next;
1.16 daniel 227: xmlFreeNs(cur);
1.6 veillard 228: cur = next;
229: }
230: }
231:
1.23 daniel 232: /**
233: * xmlNewDtd:
234: * @doc: the document pointer
235: * @name: the DTD name
236: * @ExternalID: the external ID
237: * @SystemID: the system ID
238: *
1.17 daniel 239: * Creation of a new DTD.
1.23 daniel 240: * return values: a pointer to the new DTD structure
1.17 daniel 241: */
1.28 daniel 242: xmlDtdPtr
243: xmlNewDtd(xmlDocPtr doc, const CHAR *name,
1.17 daniel 244: const CHAR *ExternalID, const CHAR *SystemID) {
245: xmlDtdPtr cur;
246:
1.31 daniel 247: if ((doc != NULL) && (doc->extSubset != NULL)) {
1.17 daniel 248: fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
1.31 daniel 249: /* !!! */ (char *) name, doc->name,
250: /* !!! */ (char *)doc->extSubset->name);
1.17 daniel 251: }
252:
253: /*
254: * Allocate a new DTD and fill the fields.
255: */
256: cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
257: if (cur == NULL) {
1.31 daniel 258: fprintf(stderr, "xmlNewDtd : malloc failed\n");
259: return(NULL);
260: }
261:
262: if (name != NULL)
263: cur->name = xmlStrdup(name);
264: else
265: cur->name = NULL;
266: if (ExternalID != NULL)
267: cur->ExternalID = xmlStrdup(ExternalID);
268: else
269: cur->ExternalID = NULL;
270: if (SystemID != NULL)
271: cur->SystemID = xmlStrdup(SystemID);
272: else
273: cur->SystemID = NULL;
274: cur->elements = NULL;
1.34 ! daniel 275: cur->attributes = NULL;
1.31 daniel 276: cur->entities = NULL;
277: if (doc != NULL)
278: doc->extSubset = cur;
279:
280: return(cur);
281: }
282:
283: /**
284: * xmlCreateIntSubset:
285: * @doc: the document pointer
286: * @name: the DTD name
287: * @ExternalID: the external ID
288: * @SystemID: the system ID
289: *
290: * Creatte the internal subset of a document
291: * return values: a pointer to the new DTD structure
292: */
293: xmlDtdPtr
294: xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
295: const CHAR *ExternalID, const CHAR *SystemID) {
296: xmlDtdPtr cur;
297:
298: if ((doc != NULL) && (doc->intSubset != NULL)) {
299: fprintf(stderr,
300: "xmlCreateIntSubset(): document %s already have an internal subset\n",
301: doc->name);
302: return(NULL);
303: }
304:
305: /*
306: * Allocate a new DTD and fill the fields.
307: */
308: cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
309: if (cur == NULL) {
310: fprintf(stderr, "xmlNewDtd : malloc failed\n");
1.17 daniel 311: return(NULL);
312: }
313:
314: if (name != NULL)
315: cur->name = xmlStrdup(name);
316: else
317: cur->name = NULL;
318: if (ExternalID != NULL)
319: cur->ExternalID = xmlStrdup(ExternalID);
320: else
321: cur->ExternalID = NULL;
322: if (SystemID != NULL)
323: cur->SystemID = xmlStrdup(SystemID);
324: else
325: cur->SystemID = NULL;
326: cur->elements = NULL;
1.34 ! daniel 327: cur->attributes = NULL;
1.17 daniel 328: cur->entities = NULL;
1.31 daniel 329: if (doc != NULL)
330: doc->intSubset = cur;
1.17 daniel 331:
332: return(cur);
333: }
334:
1.23 daniel 335: /**
336: * xmlFreeDtd:
337: * @cur: the DTD structure to free up
338: *
339: * Free a DTD structure.
1.17 daniel 340: */
1.28 daniel 341: void
342: xmlFreeDtd(xmlDtdPtr cur) {
1.17 daniel 343: if (cur == NULL) {
344: fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
345: return;
346: }
347: if (cur->name != NULL) free((char *) cur->name);
348: if (cur->SystemID != NULL) free((char *) cur->SystemID);
349: if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
350: if (cur->elements != NULL)
1.33 daniel 351: xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1.34 ! daniel 352: if (cur->attributes != NULL)
! 353: xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1.17 daniel 354: if (cur->entities != NULL)
355: xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
356: memset(cur, -1, sizeof(xmlDtd));
357: free(cur);
358: }
359:
1.23 daniel 360: /**
361: * xmlNewDoc:
362: * @version: CHAR string giving the version of XML "1.0"
363: *
364: * Create a new document
1.1 veillard 365: */
1.28 daniel 366: xmlDocPtr
367: xmlNewDoc(const CHAR *version) {
1.1 veillard 368: xmlDocPtr cur;
369:
370: if (version == NULL) {
371: fprintf(stderr, "xmlNewDoc : version == NULL\n");
372: return(NULL);
373: }
374:
375: /*
376: * Allocate a new document and fill the fields.
377: */
378: cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
379: if (cur == NULL) {
380: fprintf(stderr, "xmlNewDoc : malloc failed\n");
381: return(NULL);
382: }
383:
1.23 daniel 384: cur->type = XML_DOCUMENT_NODE;
1.7 veillard 385: cur->version = xmlStrdup(version);
1.18 daniel 386: cur->name = NULL;
1.1 veillard 387: cur->root = NULL;
1.31 daniel 388: cur->intSubset = NULL;
389: cur->extSubset = NULL;
1.19 daniel 390: cur->oldNs = NULL;
1.15 daniel 391: cur->encoding = NULL;
392: cur->standalone = -1;
1.23 daniel 393: cur->compression = xmlCompressMode;
394: #ifndef WITHOUT_CORBA
395: cur->_private = NULL;
396: cur->vepv = NULL;
397: #endif
1.1 veillard 398: return(cur);
399: }
400:
1.23 daniel 401: /**
402: * xmlFreeDoc:
403: * @cur: pointer to the document
404: * @:
405: *
406: * Free up all the structures used by a document, tree included.
1.1 veillard 407: */
1.28 daniel 408: void
409: xmlFreeDoc(xmlDocPtr cur) {
1.1 veillard 410: if (cur == NULL) {
1.31 daniel 411: #ifdef DEBUG_TREE
1.1 veillard 412: fprintf(stderr, "xmlFreeDoc : document == NULL\n");
1.31 daniel 413: #endif
1.1 veillard 414: return;
415: }
416: free((char *) cur->version);
1.17 daniel 417: if (cur->name != NULL) free((char *) cur->name);
1.15 daniel 418: if (cur->encoding != NULL) free((char *) cur->encoding);
1.1 veillard 419: if (cur->root != NULL) xmlFreeNode(cur->root);
1.31 daniel 420: if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
421: if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
422: if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1.1 veillard 423: memset(cur, -1, sizeof(xmlDoc));
424: free(cur);
425: }
426:
1.23 daniel 427: /**
1.28 daniel 428: * xmlStringLenGetNodeList:
429: * @doc: the document
430: * @value: the value of the text
431: * @int len: the length of the string value
432: *
433: * Parse the value string and build the node list associated. Should
434: * produce a flat tree with only TEXTs and ENTITY_REFs.
435: * return values: a pointer to the first child
436: */
437: xmlNodePtr
438: xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
439: xmlNodePtr ret = NULL, last = NULL;
440: xmlNodePtr node;
441: CHAR *val;
442: const CHAR *cur = value;
443: const CHAR *q;
444: xmlEntityPtr ent;
445:
446: if (value == NULL) return(NULL);
447:
448: q = cur;
449: while ((*cur != 0) && (cur - value < len)) {
450: if (*cur == '&') {
451: /*
452: * Save the current text.
453: */
454: if (cur != q) {
455: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
456: xmlNodeAddContentLen(last, q, cur - q);
457: } else {
458: node = xmlNewDocTextLen(doc, q, cur - q);
459: if (node == NULL) return(ret);
460: if (last == NULL)
461: last = ret = node;
462: else {
463: last->next = node;
464: node->prev = last;
465: last = node;
466: }
467: }
468: }
469: /*
470: * Read the entity string
471: */
472: cur++;
473: q = cur;
474: while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
475: if ((*cur == 0) || (cur - value >= len)) {
476: fprintf(stderr,
477: "xmlStringGetNodeList: unterminated entity %30s\n", q);
478: return(ret);
479: }
480: if (cur != q) {
481: /*
482: * Predefined entities don't generate nodes
483: */
484: val = xmlStrndup(q, cur - q);
485: ent = xmlGetDocEntity(doc, val);
486: if ((ent != NULL) &&
487: (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
488: if (last == NULL) {
489: node = xmlNewDocText(doc, ent->content);
490: last = ret = node;
491: } else
492: xmlNodeAddContent(last, ent->content);
493:
494: } else {
495: /*
496: * Create a new REFERENCE_REF node
497: */
498: node = xmlNewReference(doc, val);
1.30 daniel 499: if (node == NULL) {
500: if (val != NULL) free(val);
501: return(ret);
502: }
1.28 daniel 503: if (last == NULL)
504: last = ret = node;
505: else {
506: last->next = node;
507: node->prev = last;
508: last = node;
509: }
510: }
511: free(val);
512: }
513: cur++;
514: q = cur;
515: } else
516: cur++;
517: }
518: if (cur != q) {
519: /*
520: * Handle the last piece of text.
521: */
522: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
523: xmlNodeAddContentLen(last, q, cur - q);
524: } else {
525: node = xmlNewDocTextLen(doc, q, cur - q);
526: if (node == NULL) return(ret);
527: if (last == NULL)
528: last = ret = node;
529: else {
530: last->next = node;
531: node->prev = last;
532: last = node;
533: }
534: }
535: }
536: return(ret);
537: }
538:
539: /**
1.24 daniel 540: * xmlStringGetNodeList:
541: * @doc: the document
1.23 daniel 542: * @value: the value of the attribute
543: *
1.24 daniel 544: * Parse the value string and build the node list associated. Should
545: * produce a flat tree with only TEXTs and ENTITY_REFs.
1.23 daniel 546: * return values: a pointer to the first child
547: */
1.28 daniel 548: xmlNodePtr
549: xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
1.23 daniel 550: xmlNodePtr ret = NULL, last = NULL;
551: xmlNodePtr node;
552: CHAR *val;
553: const CHAR *cur = value;
554: const CHAR *q;
1.28 daniel 555: xmlEntityPtr ent;
1.23 daniel 556:
557: if (value == NULL) return(NULL);
558:
559: q = cur;
560: while (*cur != 0) {
561: if (*cur == '&') {
1.28 daniel 562: /*
563: * Save the current text.
564: */
1.23 daniel 565: if (cur != q) {
1.28 daniel 566: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
567: xmlNodeAddContentLen(last, q, cur - q);
568: } else {
569: node = xmlNewDocTextLen(doc, q, cur - q);
570: if (node == NULL) return(ret);
571: if (last == NULL)
572: last = ret = node;
573: else {
574: last->next = node;
575: node->prev = last;
576: last = node;
577: }
1.23 daniel 578: }
579: }
1.28 daniel 580: /*
581: * Read the entity string
582: */
1.23 daniel 583: cur++;
584: q = cur;
585: while ((*cur != 0) && (*cur != ';')) cur++;
586: if (*cur == 0) {
1.24 daniel 587: fprintf(stderr,
588: "xmlStringGetNodeList: unterminated entity %30s\n", q);
1.23 daniel 589: return(ret);
590: }
591: if (cur != q) {
1.28 daniel 592: /*
593: * Predefined entities don't generate nodes
594: */
1.23 daniel 595: val = xmlStrndup(q, cur - q);
1.28 daniel 596: ent = xmlGetDocEntity(doc, val);
597: if ((ent != NULL) &&
598: (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
599: if (last == NULL) {
600: node = xmlNewDocText(doc, ent->content);
601: last = ret = node;
602: } else
603: xmlNodeAddContent(last, ent->content);
604:
605: } else {
606: /*
607: * Create a new REFERENCE_REF node
608: */
609: node = xmlNewReference(doc, val);
1.30 daniel 610: if (node == NULL) {
611: if (val != NULL) free(val);
612: return(ret);
613: }
1.28 daniel 614: if (last == NULL)
615: last = ret = node;
616: else {
617: last->next = node;
618: node->prev = last;
619: last = node;
620: }
1.23 daniel 621: }
622: free(val);
623: }
624: cur++;
625: q = cur;
626: } else
627: cur++;
628: }
629: if (cur != q) {
1.28 daniel 630: /*
631: * Handle the last piece of text.
632: */
633: if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
634: xmlNodeAddContentLen(last, q, cur - q);
635: } else {
636: node = xmlNewDocTextLen(doc, q, cur - q);
637: if (node == NULL) return(ret);
638: if (last == NULL)
639: last = ret = node;
640: else {
641: last->next = node;
642: node->prev = last;
643: last = node;
644: }
1.23 daniel 645: }
646: }
647: return(ret);
648: }
649:
650: /**
1.24 daniel 651: * xmlNodeListGetString:
1.23 daniel 652: * @doc: the document
1.24 daniel 653: * @list: a Node list
1.23 daniel 654: * @inLine: should we replace entity contents or show their external form
655: *
1.24 daniel 656: * Returns the string equivalent to the text contained in the Node list
657: * made of TEXTs and ENTITY_REFs
658: * return values: a pointer to the string copy, the calller must free it.
1.23 daniel 659: */
1.28 daniel 660: CHAR *
661: xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
1.24 daniel 662: xmlNodePtr node = list;
1.23 daniel 663: CHAR *ret = NULL;
664: xmlEntityPtr ent;
665:
1.24 daniel 666: if (list == NULL) return(NULL);
1.23 daniel 667:
668: while (node != NULL) {
669: if (node->type == XML_TEXT_NODE) {
670: if (inLine)
671: ret = xmlStrcat(ret, node->content);
672: else
673: ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
674: } else if (node->type == XML_ENTITY_REF_NODE) {
675: if (inLine) {
676: ent = xmlGetDocEntity(doc, node->name);
677: if (ent != NULL)
678: ret = xmlStrcat(ret, ent->content);
679: else
680: ret = xmlStrcat(ret, node->content);
681: } else {
682: CHAR buf[2];
683: buf[0] = '&'; buf[1] = 0;
684: ret = xmlStrncat(ret, buf, 1);
685: ret = xmlStrcat(ret, node->name);
686: buf[0] = ';'; buf[1] = 0;
687: ret = xmlStrncat(ret, buf, 1);
688: }
1.24 daniel 689: }
690: #if 0
691: else {
692: fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
1.23 daniel 693: node->type);
694: }
1.24 daniel 695: #endif
1.23 daniel 696: node = node->next;
697: }
698: return(ret);
699: }
700:
701: /**
702: * xmlNewProp:
703: * @node: the holding node
704: * @name: the name of the attribute
705: * @value: the value of the attribute
706: *
707: * Create a new property carried by a node.
708: * return values: a pointer to the attribute
1.1 veillard 709: */
1.28 daniel 710: xmlAttrPtr
711: xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
1.20 daniel 712: xmlAttrPtr cur;
1.1 veillard 713:
714: if (name == NULL) {
715: fprintf(stderr, "xmlNewProp : name == NULL\n");
716: return(NULL);
717: }
718:
719: /*
720: * Allocate a new property and fill the fields.
721: */
1.20 daniel 722: cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
1.1 veillard 723: if (cur == NULL) {
724: fprintf(stderr, "xmlNewProp : malloc failed\n");
725: return(NULL);
726: }
727:
1.23 daniel 728: cur->type = XML_ATTRIBUTE_NODE;
1.1 veillard 729: cur->node = node;
1.7 veillard 730: cur->name = xmlStrdup(name);
1.1 veillard 731: if (value != NULL)
1.24 daniel 732: cur->val = xmlStringGetNodeList(node->doc, value);
1.1 veillard 733: else
1.23 daniel 734: cur->val = NULL;
735: #ifndef WITHOUT_CORBA
736: cur->_private = NULL;
737: cur->vepv = NULL;
738: #endif
1.17 daniel 739:
740: /*
741: * Add it at the end to preserve parsing order ...
742: */
743: cur->next = NULL;
1.1 veillard 744: if (node != NULL) {
1.17 daniel 745: if (node->properties == NULL) {
746: node->properties = cur;
747: } else {
1.20 daniel 748: xmlAttrPtr prev = node->properties;
1.17 daniel 749:
750: while (prev->next != NULL) prev = prev->next;
751: prev->next = cur;
752: }
753: }
1.1 veillard 754: return(cur);
755: }
756:
1.23 daniel 757: /**
758: * xmlNewDocProp:
759: * @doc: the document
760: * @name: the name of the attribute
761: * @value: the value of the attribute
762: *
763: * Create a new property carried by a document.
764: * return values: a pointer to the attribute
765: */
1.28 daniel 766: xmlAttrPtr
767: xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
1.23 daniel 768: xmlAttrPtr cur;
769:
770: if (name == NULL) {
771: fprintf(stderr, "xmlNewProp : name == NULL\n");
772: return(NULL);
773: }
774:
775: /*
776: * Allocate a new property and fill the fields.
777: */
778: cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
779: if (cur == NULL) {
780: fprintf(stderr, "xmlNewProp : malloc failed\n");
781: return(NULL);
782: }
783:
784: cur->type = XML_ATTRIBUTE_NODE;
785: cur->node = NULL;
786: cur->name = xmlStrdup(name);
787: if (value != NULL)
1.24 daniel 788: cur->val = xmlStringGetNodeList(doc, value);
1.23 daniel 789: else
790: cur->val = NULL;
791: #ifndef WITHOUT_CORBA
792: cur->_private = NULL;
793: cur->vepv = NULL;
794: #endif
795:
796: cur->next = NULL;
797: return(cur);
798: }
799:
800: /**
801: * xmlFreePropList:
802: * @cur: the first property in the list
803: *
804: * Free a property and all its siblings, all the childs are freed too.
1.1 veillard 805: */
1.28 daniel 806: void
807: xmlFreePropList(xmlAttrPtr cur) {
1.20 daniel 808: xmlAttrPtr next;
1.1 veillard 809: if (cur == NULL) {
810: fprintf(stderr, "xmlFreePropList : property == NULL\n");
811: return;
812: }
813: while (cur != NULL) {
814: next = cur->next;
815: xmlFreeProp(cur);
816: cur = next;
817: }
818: }
819:
1.23 daniel 820: /**
821: * xmlFreeProp:
822: * @cur: the first property in the list
823: *
824: * Free one property, all the childs are freed too.
1.1 veillard 825: */
1.28 daniel 826: void
827: xmlFreeProp(xmlAttrPtr cur) {
1.1 veillard 828: if (cur == NULL) {
829: fprintf(stderr, "xmlFreeProp : property == NULL\n");
830: return;
831: }
832: if (cur->name != NULL) free((char *) cur->name);
1.23 daniel 833: if (cur->val != NULL) xmlFreeNodeList(cur->val);
1.20 daniel 834: memset(cur, -1, sizeof(xmlAttr));
1.1 veillard 835: free(cur);
836: }
837:
1.23 daniel 838: /**
839: * xmlNewNode:
840: * @ns: namespace if any
841: * @name: the node name
842: * @content: the text content if any
843: *
844: * Creation of a new node element. @ns and @content are optionnal (NULL).
1.24 daniel 845: * If content is non NULL, a child list containing the TEXTs and
846: * ENTITY_REFs node will be created.
1.23 daniel 847: * return values: a pointer to the new node object.
1.1 veillard 848: */
1.28 daniel 849: xmlNodePtr
850: xmlNewNode(xmlNsPtr ns, const CHAR *name) {
1.1 veillard 851: xmlNodePtr cur;
852:
853: if (name == NULL) {
854: fprintf(stderr, "xmlNewNode : name == NULL\n");
855: return(NULL);
856: }
857:
858: /*
859: * Allocate a new node and fill the fields.
860: */
861: cur = (xmlNodePtr) malloc(sizeof(xmlNode));
862: if (cur == NULL) {
863: fprintf(stderr, "xmlNewNode : malloc failed\n");
864: return(NULL);
865: }
866:
1.23 daniel 867: cur->type = XML_ELEMENT_NODE;
868: cur->doc = NULL;
1.1 veillard 869: cur->parent = NULL;
1.23 daniel 870: cur->next = NULL;
871: cur->prev = NULL;
872: cur->childs = NULL;
1.32 daniel 873: cur->last = NULL;
1.23 daniel 874: cur->properties = NULL;
1.22 daniel 875: cur->name = xmlStrdup(name);
1.16 daniel 876: cur->ns = ns;
1.19 daniel 877: cur->nsDef = NULL;
1.24 daniel 878: cur->content = NULL;
1.23 daniel 879: #ifndef WITHOUT_CORBA
880: cur->_private = NULL;
881: cur->vepv = NULL;
882: #endif
1.1 veillard 883: return(cur);
884: }
885:
1.23 daniel 886: /**
887: * xmlNewDocNode:
888: * @doc: the document
889: * @ns: namespace if any
890: * @name: the node name
891: * @content: the text content if any
892: *
893: * Creation of a new node element within a document. @ns and @content
894: * are optionnal (NULL).
895: * return values: a pointer to the new node object.
896: */
1.28 daniel 897: xmlNodePtr
898: xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1.23 daniel 899: const CHAR *name, CHAR *content) {
900: xmlNodePtr cur;
901:
1.24 daniel 902: cur = xmlNewNode(ns, name);
903: if (cur != NULL) {
904: cur->doc = doc;
1.32 daniel 905: if (content != NULL) {
1.24 daniel 906: cur->childs = xmlStringGetNodeList(doc, content);
1.34 ! daniel 907: UPDATE_LAST_CHILD(cur)
1.32 daniel 908: }
1.24 daniel 909: }
1.23 daniel 910: return(cur);
911: }
912:
913:
914: /**
915: * xmlNewText:
916: * @content: the text content
917: *
918: * Creation of a new text node.
919: * return values: a pointer to the new node object.
1.3 veillard 920: */
1.28 daniel 921: xmlNodePtr
922: xmlNewText(const CHAR *content) {
1.3 veillard 923: xmlNodePtr cur;
924:
925: /*
926: * Allocate a new node and fill the fields.
927: */
928: cur = (xmlNodePtr) malloc(sizeof(xmlNode));
929: if (cur == NULL) {
1.19 daniel 930: fprintf(stderr, "xmlNewText : malloc failed\n");
1.3 veillard 931: return(NULL);
932: }
933:
1.23 daniel 934: cur->type = XML_TEXT_NODE;
935: cur->doc = NULL;
1.3 veillard 936: cur->parent = NULL;
937: cur->next = NULL;
1.23 daniel 938: cur->prev = NULL;
1.3 veillard 939: cur->childs = NULL;
1.32 daniel 940: cur->last = NULL;
1.3 veillard 941: cur->properties = NULL;
1.23 daniel 942: cur->type = XML_TEXT_NODE;
1.18 daniel 943: cur->name = xmlStrdup(xmlStringText);
1.16 daniel 944: cur->ns = NULL;
1.19 daniel 945: cur->nsDef = NULL;
1.3 veillard 946: if (content != NULL)
1.7 veillard 947: cur->content = xmlStrdup(content);
1.3 veillard 948: else
949: cur->content = NULL;
950: return(cur);
951: }
952:
1.23 daniel 953: /**
954: * xmlNewReference:
955: * @doc: the document
956: * @name: the reference name, or the reference string with & and ;
957: *
958: * Creation of a new reference node.
959: * return values: a pointer to the new node object.
960: */
1.28 daniel 961: xmlNodePtr
962: xmlNewReference(xmlDocPtr doc, const CHAR *name) {
1.23 daniel 963: xmlNodePtr cur;
964: xmlEntityPtr ent;
965:
966: /*
967: * Allocate a new node and fill the fields.
968: */
969: cur = (xmlNodePtr) malloc(sizeof(xmlNode));
970: if (cur == NULL) {
971: fprintf(stderr, "xmlNewText : malloc failed\n");
972: return(NULL);
973: }
974:
975: cur->type = XML_ENTITY_REF_NODE;
1.28 daniel 976: cur->doc = doc;
1.23 daniel 977: cur->parent = NULL;
978: cur->next = NULL;
979: cur->prev = NULL;
980: cur->childs = NULL;
1.32 daniel 981: cur->last = NULL;
1.23 daniel 982: cur->properties = NULL;
983: if (name[0] == '&') {
984: int len;
985: name++;
986: len = xmlStrlen(name);
987: if (name[len - 1] == ';')
988: cur->name = xmlStrndup(name, len - 1);
989: else
990: cur->name = xmlStrndup(name, len);
991: } else
992: cur->name = xmlStrdup(name);
993: cur->ns = NULL;
994: cur->nsDef = NULL;
995:
996: ent = xmlGetDocEntity(doc, cur->name);
997: if (ent != NULL)
998: cur->content = ent->content;
999: else
1000: cur->content = NULL;
1001: return(cur);
1002: }
1003:
1004: /**
1005: * xmlNewDocText:
1006: * @doc: the document
1007: * @content: the text content
1008: *
1009: * Creation of a new text node within a document.
1010: * return values: a pointer to the new node object.
1011: */
1.28 daniel 1012: xmlNodePtr
1013: xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
1.23 daniel 1014: xmlNodePtr cur;
1015:
1016: cur = xmlNewText(content);
1017: if (cur != NULL) cur->doc = doc;
1018: return(cur);
1019: }
1020:
1021: /**
1022: * xmlNewTextLen:
1023: * @content: the text content
1024: * @len: the text len.
1025: *
1026: * Creation of a new text node with an extra parameter for the content's lenght
1027: * return values: a pointer to the new node object.
1.21 daniel 1028: */
1.28 daniel 1029: xmlNodePtr
1030: xmlNewTextLen(const CHAR *content, int len) {
1.21 daniel 1031: xmlNodePtr cur;
1032:
1033: /*
1034: * Allocate a new node and fill the fields.
1035: */
1036: cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1037: if (cur == NULL) {
1038: fprintf(stderr, "xmlNewText : malloc failed\n");
1039: return(NULL);
1040: }
1041:
1.23 daniel 1042: cur->type = XML_TEXT_NODE;
1043: cur->doc = NULL;
1.21 daniel 1044: cur->parent = NULL;
1.23 daniel 1045: cur->prev = NULL;
1.21 daniel 1046: cur->next = NULL;
1047: cur->childs = NULL;
1.32 daniel 1048: cur->last = NULL;
1.21 daniel 1049: cur->properties = NULL;
1.23 daniel 1050: cur->type = XML_TEXT_NODE;
1.21 daniel 1051: cur->name = xmlStrdup(xmlStringText);
1052: cur->ns = NULL;
1053: cur->nsDef = NULL;
1054: if (content != NULL)
1055: cur->content = xmlStrndup(content, len);
1056: else
1057: cur->content = NULL;
1058: return(cur);
1059: }
1060:
1.23 daniel 1061: /**
1062: * xmlNewDocTextLen:
1063: * @doc: the document
1064: * @content: the text content
1065: * @len: the text len.
1066: *
1067: * Creation of a new text node with an extra content lenght parameter. The
1068: * text node pertain to a given document.
1069: * return values: a pointer to the new node object.
1070: */
1.28 daniel 1071: xmlNodePtr
1072: xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
1.23 daniel 1073: xmlNodePtr cur;
1074:
1075: cur = xmlNewTextLen(content, len);
1076: if (cur != NULL) cur->doc = doc;
1077: return(cur);
1078: }
1079:
1080: /**
1081: * xmlNewComment:
1082: * @content: the comment content
1083: *
1084: * Creation of a new node containing a comment.
1085: * return values: a pointer to the new node object.
1.14 daniel 1086: */
1.28 daniel 1087: xmlNodePtr
1088: xmlNewComment(CHAR *content) {
1.14 daniel 1089: xmlNodePtr cur;
1090:
1091: /*
1092: * Allocate a new node and fill the fields.
1093: */
1094: cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1095: if (cur == NULL) {
1.19 daniel 1096: fprintf(stderr, "xmlNewComment : malloc failed\n");
1.14 daniel 1097: return(NULL);
1098: }
1099:
1.23 daniel 1100: cur->type = XML_COMMENT_NODE;
1101: cur->doc = NULL;
1.14 daniel 1102: cur->parent = NULL;
1.23 daniel 1103: cur->prev = NULL;
1.14 daniel 1104: cur->next = NULL;
1105: cur->childs = NULL;
1.32 daniel 1106: cur->last = NULL;
1.14 daniel 1107: cur->properties = NULL;
1.23 daniel 1108: cur->type = XML_COMMENT_NODE;
1.18 daniel 1109: cur->name = xmlStrdup(xmlStringText);
1.16 daniel 1110: cur->ns = NULL;
1.19 daniel 1111: cur->nsDef = NULL;
1.14 daniel 1112: if (content != NULL)
1113: cur->content = xmlStrdup(content);
1114: else
1115: cur->content = NULL;
1116: return(cur);
1117: }
1118:
1.23 daniel 1119: /**
1120: * xmlNewComment:
1121: * @doc: the document
1122: * @content: the comment content
1123: *
1124: * Creation of a new node containing a commentwithin a document.
1125: * return values: a pointer to the new node object.
1126: */
1.28 daniel 1127: xmlNodePtr
1128: xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
1.23 daniel 1129: xmlNodePtr cur;
1130:
1131: cur = xmlNewComment(content);
1132: if (cur != NULL) cur->doc = doc;
1133: return(cur);
1134: }
1135:
1136: /**
1137: * xmlNewChild:
1138: * @parent: the parent node
1139: * @ns: a namespace if any
1140: * @name: the name of the child
1141: * @content: the content of the child if any.
1142: *
1143: *
1144: * Creation of a new child element, added at the end of @parent childs list.
1.24 daniel 1145: * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1146: * a child list containing the TEXTs and ENTITY_REFs node will be created.
1.23 daniel 1147: * return values: a pointer to the new node object.
1.1 veillard 1148: */
1.28 daniel 1149: xmlNodePtr
1150: xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1.7 veillard 1151: const CHAR *name, CHAR *content) {
1.1 veillard 1152: xmlNodePtr cur, prev;
1153:
1154: if (parent == NULL) {
1155: fprintf(stderr, "xmlNewChild : parent == NULL\n");
1156: return(NULL);
1157: }
1158:
1159: if (name == NULL) {
1160: fprintf(stderr, "xmlNewChild : name == NULL\n");
1161: return(NULL);
1162: }
1163:
1164: /*
1165: * Allocate a new node
1166: */
1.16 daniel 1167: if (ns == NULL)
1.24 daniel 1168: cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1.1 veillard 1169: else
1.24 daniel 1170: cur = xmlNewDocNode(parent->doc, ns, name, content);
1.1 veillard 1171: if (cur == NULL) return(NULL);
1172:
1173: /*
1174: * add the new element at the end of the childs list.
1175: */
1.25 daniel 1176: cur->type = XML_ELEMENT_NODE;
1.1 veillard 1177: cur->parent = parent;
1.23 daniel 1178: cur->doc = parent->doc;
1.1 veillard 1179: if (parent->childs == NULL) {
1180: parent->childs = cur;
1.32 daniel 1181: parent->last = cur;
1.1 veillard 1182: } else {
1.32 daniel 1183: prev = parent->last;
1.1 veillard 1184: prev->next = cur;
1.23 daniel 1185: cur->prev = prev;
1.32 daniel 1186: parent->last = cur;
1.1 veillard 1187: }
1188:
1189: return(cur);
1190: }
1191:
1.23 daniel 1192: /**
1193: * xmlAddChild:
1194: * @parent: the parent node
1195: * @cur: the child node
1196: *
1197: * Add a new child element, to @parent, at the end of the child list.
1198: * return values: the child or NULL in case of error.
1.2 veillard 1199: */
1.28 daniel 1200: xmlNodePtr
1201: xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
1.2 veillard 1202: xmlNodePtr prev;
1203:
1204: if (parent == NULL) {
1205: fprintf(stderr, "xmladdChild : parent == NULL\n");
1206: return(NULL);
1207: }
1208:
1209: if (cur == NULL) {
1210: fprintf(stderr, "xmladdChild : child == NULL\n");
1211: return(NULL);
1212: }
1213:
1.23 daniel 1214: if ((cur->doc != NULL) && (parent->doc != NULL) &&
1215: (cur->doc != parent->doc)) {
1216: fprintf(stderr, "Elements moved to a different document\n");
1217: }
1218:
1.2 veillard 1219: /*
1220: * add the new element at the end of the childs list.
1221: */
1222: cur->parent = parent;
1.23 daniel 1223: cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
1.32 daniel 1224:
1.24 daniel 1225: /*
1226: * Handle the case where parent->content != NULL, in that case it will
1227: * create a intermediate TEXT node.
1228: */
1229: if (parent->content != NULL) {
1230: xmlNodePtr text;
1231:
1232: text = xmlNewDocText(parent->doc, parent->content);
1233: if (text != NULL) {
1234: text->next = parent->childs;
1235: if (text->next != NULL)
1236: text->next->prev = text;
1237: parent->childs = text;
1.34 ! daniel 1238: UPDATE_LAST_CHILD(parent)
1.24 daniel 1239: free(parent->content);
1240: parent->content = NULL;
1241: }
1242: }
1.2 veillard 1243: if (parent->childs == NULL) {
1244: parent->childs = cur;
1.32 daniel 1245: parent->last = cur;
1.2 veillard 1246: } else {
1.32 daniel 1247: prev = parent->last;
1.2 veillard 1248: prev->next = cur;
1.23 daniel 1249: cur->prev = prev;
1.32 daniel 1250: parent->last = cur;
1.2 veillard 1251: }
1252:
1253: return(cur);
1254: }
1255:
1.23 daniel 1256: /**
1257: * xmlGetLastChild:
1258: * @parent: the parent node
1259: *
1260: * Search the last child of a node.
1261: * return values: the last child or NULL if none.
1.21 daniel 1262: */
1.28 daniel 1263: xmlNodePtr
1264: xmlGetLastChild(xmlNodePtr parent) {
1.21 daniel 1265: if (parent == NULL) {
1266: fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1267: return(NULL);
1268: }
1.32 daniel 1269: return(parent->last);
1.21 daniel 1270: }
1271:
1.23 daniel 1272: /**
1273: * xmlFreeNodeList:
1274: * @cur: the first node in the list
1275: *
1276: * Free a node and all its siblings, this is a recursive behaviour, all
1277: * the childs are freed too.
1.1 veillard 1278: */
1.28 daniel 1279: void
1280: xmlFreeNodeList(xmlNodePtr cur) {
1.1 veillard 1281: xmlNodePtr next;
1282: if (cur == NULL) {
1283: fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1284: return;
1285: }
1286: while (cur != NULL) {
1287: next = cur->next;
1288: xmlFreeNode(cur);
1289: cur = next;
1290: }
1291: }
1292:
1.23 daniel 1293: /**
1294: * xmlFreeNode:
1295: * @cur: the node
1296: *
1297: * Free a node, this is a recursive behaviour, all the childs are freed too.
1.1 veillard 1298: */
1.28 daniel 1299: void
1300: xmlFreeNode(xmlNodePtr cur) {
1.1 veillard 1301: if (cur == NULL) {
1302: fprintf(stderr, "xmlFreeNode : node == NULL\n");
1303: return;
1304: }
1.23 daniel 1305: cur->doc = NULL;
1306: cur->parent = NULL;
1307: cur->next = NULL;
1308: cur->prev = NULL;
1309: if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
1.1 veillard 1310: if (cur->properties != NULL) xmlFreePropList(cur->properties);
1.23 daniel 1311: if (cur->type != XML_ENTITY_REF_NODE)
1312: if (cur->content != NULL) free(cur->content);
1.7 veillard 1313: if (cur->name != NULL) free((char *) cur->name);
1.19 daniel 1314: if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1.1 veillard 1315: memset(cur, -1, sizeof(xmlNode));
1316: free(cur);
1317: }
1318:
1.28 daniel 1319: /**
1320: * xmlUnlinkNode:
1321: * @cur: the node
1322: *
1323: * Unlink a node from it's current context, the node is not freed
1324: */
1325: void
1326: xmlUnlinkNode(xmlNodePtr cur) {
1327: if (cur == NULL) {
1328: fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1329: return;
1330: }
1331: if ((cur->parent != NULL) && (cur->parent->childs == cur))
1332: cur->parent->childs = cur->next;
1.32 daniel 1333: if ((cur->parent != NULL) && (cur->parent->last == cur))
1334: cur->parent->last = cur->prev;
1.28 daniel 1335: if (cur->next != NULL)
1336: cur->next->prev = cur->prev;
1337: if (cur->prev != NULL)
1338: cur->prev->next = cur->next;
1339: cur->next = cur->prev = NULL;
1340: cur->parent = NULL;
1341: }
1342:
1.1 veillard 1343: /************************************************************************
1344: * *
1.31 daniel 1345: * Copy operations *
1346: * *
1347: ************************************************************************/
1348:
1349: /**
1350: * xmlCopyNamespace:
1351: * @cur: the namespace
1352: *
1353: * Do a copy of the namespace.
1354: *
1355: * Returns: a new xmlNsPtr, or NULL in case of error.
1356: */
1357: xmlNsPtr
1358: xmlCopyNamespace(xmlNsPtr cur) {
1359: xmlNsPtr ret;
1360:
1361: if (cur == NULL) return(NULL);
1362: switch (cur->type) {
1363: case XML_GLOBAL_NAMESPACE:
1364: ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1365: break;
1366: case XML_LOCAL_NAMESPACE:
1367: ret = xmlNewNs(NULL, cur->href, cur->prefix);
1368: break;
1369: default:
1370: fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1371: return(NULL);
1372: }
1373: return(ret);
1374: }
1375:
1376: /**
1377: * xmlCopyNamespaceList:
1378: * @cur: the first namespace
1379: *
1380: * Do a copy of an namespace list.
1381: *
1382: * Returns: a new xmlNsPtr, or NULL in case of error.
1383: */
1384: xmlNsPtr
1385: xmlCopyNamespaceList(xmlNsPtr cur) {
1386: xmlNsPtr ret = NULL;
1387: xmlNsPtr p = NULL,q;
1388:
1389: while (cur != NULL) {
1390: q = xmlCopyNamespace(cur);
1391: if (p == NULL) {
1392: ret = p = q;
1393: } else {
1394: p->next = q;
1395: p = q;
1396: }
1397: cur = cur->next;
1398: }
1399: return(ret);
1400: }
1401:
1402: /**
1403: * xmlCopyProp:
1404: * @cur: the attribute
1405: *
1406: * Do a copy of the attribute.
1407: *
1408: * Returns: a new xmlAttrPtr, or NULL in case of error.
1409: */
1410: xmlAttrPtr
1411: xmlCopyProp(xmlAttrPtr cur) {
1412: xmlAttrPtr ret;
1413:
1414: if (cur == NULL) return(NULL);
1415: if (cur->val != NULL)
1416: ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1417: else
1418: ret = xmlNewDocProp(NULL, cur->name, NULL);
1419: if (ret == NULL) return(NULL);
1420: if (cur->val != NULL)
1421: ret->val = xmlCopyNodeList(cur->val);
1422: return(ret);
1423: }
1424:
1425: /**
1426: * xmlCopyPropList:
1427: * @cur: the first attribute
1428: *
1429: * Do a copy of an attribute list.
1430: *
1431: * Returns: a new xmlAttrPtr, or NULL in case of error.
1432: */
1433: xmlAttrPtr
1434: xmlCopyPropList(xmlAttrPtr cur) {
1435: xmlAttrPtr ret = NULL;
1436: xmlAttrPtr p = NULL,q;
1437:
1438: while (cur != NULL) {
1439: q = xmlCopyProp(cur);
1440: if (p == NULL) {
1441: ret = p = q;
1442: } else {
1443: p->next = q;
1444: p = q;
1445: }
1446: cur = cur->next;
1447: }
1448: return(ret);
1449: }
1450:
1451: /*
1452: * NOTE about the CopyNode operations !
1453: *
1454: * They are splitted into external and internal parts for one
1455: * tricky reason: namespaces. Doing a direct copy of a node
1456: * say RPM:Copyright without changing the namespace pointer to
1457: * something else can produce stale links. One way to do it is
1458: * to keep a reference counter but this doesn't work as soon
1459: * as one move the element or the subtree out of the scope of
1460: * the existing namespace. The actual solution seems to add
1461: * a copy of the namespace at the top of the copied tree if
1462: * not available in the subtree.
1463: * Hence two functions, the public front-end call the inner ones
1464: */
1465:
1466: static xmlNodePtr
1467: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1468:
1469: static xmlNodePtr
1470: xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1471: int recursive) {
1472: xmlNodePtr ret;
1473:
1474: if (node == NULL) return(NULL);
1475: /*
1476: * Allocate a new node and fill the fields.
1477: */
1478: ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1479: if (ret == NULL) {
1480: fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1481: return(NULL);
1482: }
1483:
1484: ret->type = node->type;
1485: ret->doc = doc;
1486: ret->parent = parent;
1487: ret->next = NULL;
1488: ret->prev = NULL;
1489: ret->childs = NULL;
1.32 daniel 1490: ret->last = NULL;
1.31 daniel 1491: ret->properties = NULL;
1492: if (node->name != NULL)
1493: ret->name = xmlStrdup(node->name);
1494: else
1495: ret->name = NULL;
1496: ret->ns = NULL;
1497: ret->nsDef = NULL;
1498: if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1499: ret->content = xmlStrdup(node->content);
1500: else
1501: ret->content = NULL;
1502: #ifndef WITHOUT_CORBA
1503: ret->_private = NULL;
1504: ret->vepv = NULL;
1505: #endif
1506: if (parent != NULL)
1507: xmlAddChild(parent, ret);
1508:
1509: if (!recursive) return(ret);
1510: if (node->properties != NULL)
1511: ret->properties = xmlCopyPropList(node->properties);
1512: if (node->nsDef != NULL)
1513: ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1514:
1515: if (node->ns != NULL) {
1516: xmlNsPtr ns;
1517:
1518: ns = xmlSearchNs(doc, ret, node->ns->prefix);
1519: if (ns == NULL) {
1520: /*
1521: * Humm, we are copying an element whose namespace is defined
1522: * out of the new tree scope. Search it in the original tree
1523: * and add it at the top of the new tree
1524: */
1525: ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1526: if (ns != NULL) {
1527: xmlNodePtr root = ret;
1528:
1529: while (root->parent != NULL) root = root->parent;
1530: xmlNewNs(root, ns->href, ns->prefix);
1531: }
1532: } else {
1533: /*
1534: * reference the existing namespace definition in our own tree.
1535: */
1536: ret->ns = ns;
1537: }
1538: }
1539: if (node->childs != NULL)
1540: ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
1.34 ! daniel 1541: UPDATE_LAST_CHILD(ret)
1.31 daniel 1542: return(ret);
1543: }
1544:
1545: static xmlNodePtr
1546: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1547: xmlNodePtr ret = NULL;
1548: xmlNodePtr p = NULL,q;
1549:
1550: while (node != NULL) {
1551: q = xmlStaticCopyNode(node, doc, parent, 1);
1552: if (parent == NULL) {
1553: if (ret == NULL) ret = q;
1554: } else {
1555: if (ret == NULL) {
1556: q->prev = NULL;
1557: ret = p = q;
1558: } else {
1559: p->next = q;
1560: q->prev = p;
1561: p = q;
1562: }
1563: }
1564: node = node->next;
1565: }
1566: return(ret);
1567: }
1568:
1569: /**
1570: * xmlCopyNode:
1571: * @node: the node
1572: * @recursive: if 1 do a recursive copy.
1573: *
1574: * Do a copy of the node.
1575: *
1576: * Returns: a new xmlNodePtr, or NULL in case of error.
1577: */
1578: xmlNodePtr
1579: xmlCopyNode(xmlNodePtr node, int recursive) {
1580: xmlNodePtr ret;
1581:
1582: ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1583: return(ret);
1584: }
1585:
1586: /**
1587: * xmlCopyNodeList:
1588: * @node: the first node in the list.
1589: *
1590: * Do a recursive copy of the node list.
1591: *
1592: * Returns: a new xmlNodePtr, or NULL in case of error.
1593: */
1594: xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1595: xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1596: return(ret);
1597: }
1598:
1599: /**
1600: * xmlCopyElement:
1601: * @elem: the element
1602: *
1603: * Do a copy of the element definition.
1604: *
1605: * Returns: a new xmlElementPtr, or NULL in case of error.
1606: xmlElementPtr
1607: xmlCopyElement(xmlElementPtr elem) {
1608: xmlElementPtr ret;
1609:
1610: if (elem == NULL) return(NULL);
1611: ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1612: if (ret == NULL) return(NULL);
1613: if (!recursive) return(ret);
1614: if (elem->properties != NULL)
1615: ret->properties = xmlCopyPropList(elem->properties);
1616:
1617: if (elem->nsDef != NULL)
1618: ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1619: if (elem->childs != NULL)
1620: ret->childs = xmlCopyElementList(elem->childs);
1621: return(ret);
1622: }
1623: */
1624:
1625: /**
1626: * xmlCopyDtd:
1627: * @dtd: the dtd
1628: *
1629: * Do a copy of the dtd.
1630: *
1631: * Returns: a new xmlDtdPtr, or NULL in case of error.
1632: */
1633: xmlDtdPtr
1634: xmlCopyDtd(xmlDtdPtr dtd) {
1635: xmlDtdPtr ret;
1636:
1637: if (dtd == NULL) return(NULL);
1638: ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1639: if (ret == NULL) return(NULL);
1640: if (dtd->entities != NULL)
1641: ret->entities = (void *) xmlCopyEntitiesTable(
1642: (xmlEntitiesTablePtr) dtd->entities);
1643: /*
1644: * TODO: support for Element definitions.
1645: */
1646: return(ret);
1647: }
1648:
1649: /**
1650: * xmlCopyDoc:
1651: * @doc: the document
1652: * @recursive: if 1 do a recursive copy.
1653: *
1654: * Do a copy of the document info. If recursive, the content tree will
1655: * be copied too as well as Dtd, namespaces and entities.
1656: *
1657: * Returns: a new xmlDocPtr, or NULL in case of error.
1658: */
1659: xmlDocPtr
1660: xmlCopyDoc(xmlDocPtr doc, int recursive) {
1661: xmlDocPtr ret;
1662:
1663: if (doc == NULL) return(NULL);
1664: ret = xmlNewDoc(doc->version);
1665: if (ret == NULL) return(NULL);
1666: if (doc->name != NULL)
1667: ret->name = strdup(doc->name);
1668: if (doc->encoding != NULL)
1669: ret->encoding = xmlStrdup(doc->encoding);
1670: ret->compression = doc->compression;
1671: ret->standalone = doc->standalone;
1672: if (!recursive) return(ret);
1673:
1674: if (doc->intSubset != NULL)
1675: ret->intSubset = xmlCopyDtd(doc->intSubset);
1676: if (doc->oldNs != NULL)
1677: ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1678: if (doc->root != NULL)
1679: ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1680: return(ret);
1681: }
1682:
1683: /************************************************************************
1684: * *
1.1 veillard 1685: * Content access functions *
1686: * *
1687: ************************************************************************/
1688:
1.23 daniel 1689: /**
1.28 daniel 1690: * xmlNodeGetContent:
1691: * @cur: the node being read
1692: *
1693: * Read the value of a node, this can be either the text carried
1694: * directly by this node if it's a TEXT node or the aggregate string
1695: * of the values carried by this node child's (TEXT and ENTITY_REF).
1696: * Entity references are substitued.
1697: * Return value: a new CHAR * or NULL if no content is available.
1698: */
1699: CHAR *
1700: xmlNodeGetContent(xmlNodePtr cur) {
1701: if (cur == NULL) return(NULL);
1702: switch (cur->type) {
1703: case XML_DOCUMENT_FRAG_NODE:
1704: case XML_ELEMENT_NODE:
1705: return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1706: break;
1707: case XML_ATTRIBUTE_NODE:
1708: case XML_CDATA_SECTION_NODE:
1709: case XML_ENTITY_REF_NODE:
1710: case XML_ENTITY_NODE:
1711: case XML_PI_NODE:
1712: case XML_COMMENT_NODE:
1713: case XML_DOCUMENT_NODE:
1714: case XML_DOCUMENT_TYPE_NODE:
1715: case XML_NOTATION_NODE:
1716: return(NULL);
1717: case XML_TEXT_NODE:
1718: if (cur->content != NULL)
1719: return(xmlStrdup(cur->content));
1720: return(NULL);
1721: }
1722: return(NULL);
1723: }
1724:
1725: /**
1.23 daniel 1726: * xmlNodeSetContent:
1727: * @cur: the node being modified
1728: * @content: the new value of the content
1729: *
1730: * Replace the content of a node.
1.1 veillard 1731: */
1.28 daniel 1732: void
1733: xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
1.1 veillard 1734: if (cur == NULL) {
1735: fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1736: return;
1737: }
1.28 daniel 1738: switch (cur->type) {
1739: case XML_DOCUMENT_FRAG_NODE:
1740: case XML_ELEMENT_NODE:
1741: if (cur->content != NULL) {
1742: free(cur->content);
1743: cur->content = NULL;
1744: }
1745: if (cur->childs != NULL) xmlFreeNode(cur->childs);
1746: cur->childs = xmlStringGetNodeList(cur->doc, content);
1.34 ! daniel 1747: UPDATE_LAST_CHILD(cur)
1.28 daniel 1748: break;
1749: case XML_ATTRIBUTE_NODE:
1750: break;
1751: case XML_TEXT_NODE:
1752: case XML_CDATA_SECTION_NODE:
1753: case XML_ENTITY_REF_NODE:
1754: case XML_ENTITY_NODE:
1755: case XML_PI_NODE:
1756: case XML_COMMENT_NODE:
1757: if (cur->content != NULL) free(cur->content);
1758: if (cur->childs != NULL) xmlFreeNode(cur->childs);
1.32 daniel 1759: cur->last = cur->childs = NULL;
1.28 daniel 1760: if (content != NULL)
1761: cur->content = xmlStrdup(content);
1762: else
1763: cur->content = NULL;
1764: case XML_DOCUMENT_NODE:
1765: case XML_DOCUMENT_TYPE_NODE:
1766: break;
1767: case XML_NOTATION_NODE:
1768: break;
1769: }
1.1 veillard 1770: }
1771:
1.23 daniel 1772: /**
1773: * xmlNodeSetContentLen:
1774: * @cur: the node being modified
1775: * @content: the new value of the content
1776: * @len: the size of @content
1777: *
1778: * Replace the content of a node.
1.21 daniel 1779: */
1.28 daniel 1780: void
1781: xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
1.21 daniel 1782: if (cur == NULL) {
1.28 daniel 1783: fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
1.21 daniel 1784: return;
1785: }
1.28 daniel 1786: switch (cur->type) {
1787: case XML_DOCUMENT_FRAG_NODE:
1788: case XML_ELEMENT_NODE:
1789: if (cur->content != NULL) {
1790: free(cur->content);
1791: cur->content = NULL;
1792: }
1793: if (cur->childs != NULL) xmlFreeNode(cur->childs);
1794: cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
1.34 ! daniel 1795: UPDATE_LAST_CHILD(cur)
1.28 daniel 1796: break;
1797: case XML_ATTRIBUTE_NODE:
1798: break;
1799: case XML_TEXT_NODE:
1800: case XML_CDATA_SECTION_NODE:
1801: case XML_ENTITY_REF_NODE:
1802: case XML_ENTITY_NODE:
1803: case XML_PI_NODE:
1804: case XML_COMMENT_NODE:
1805: if (cur->content != NULL) free(cur->content);
1806: if (cur->childs != NULL) xmlFreeNode(cur->childs);
1.32 daniel 1807: cur->childs = cur->last = NULL;
1.28 daniel 1808: if (content != NULL)
1809: cur->content = xmlStrndup(content, len);
1810: else
1811: cur->content = NULL;
1812: case XML_DOCUMENT_NODE:
1813: case XML_DOCUMENT_TYPE_NODE:
1814: break;
1815: case XML_NOTATION_NODE:
1816: if (cur->content != NULL) free(cur->content);
1.32 daniel 1817: if (cur->childs != NULL) xmlFreeNode(cur->childs);
1818: cur->childs = cur->last = NULL;
1.28 daniel 1819: if (content != NULL)
1820: cur->content = xmlStrndup(content, len);
1821: else
1822: cur->content = NULL;
1823: break;
1824: }
1.21 daniel 1825: }
1826:
1.23 daniel 1827: /**
1.28 daniel 1828: * xmlNodeAddContentLen:
1.23 daniel 1829: * @cur: the node being modified
1830: * @content: extra content
1.28 daniel 1831: * @len: the size of @content
1.23 daniel 1832: *
1833: * Append the extra substring to the node content.
1.21 daniel 1834: */
1.28 daniel 1835: void
1836: xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
1.21 daniel 1837: if (cur == NULL) {
1.28 daniel 1838: fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1.21 daniel 1839: return;
1840: }
1.28 daniel 1841: if (len <= 0) return;
1842: switch (cur->type) {
1843: case XML_DOCUMENT_FRAG_NODE:
1844: case XML_ELEMENT_NODE: {
1845: xmlNodePtr last = NULL, new;
1846:
1847: if (cur->childs != NULL) {
1.32 daniel 1848: last = cur->last;
1.28 daniel 1849: } else {
1850: if (cur->content != NULL) {
1851: cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
1.34 ! daniel 1852: UPDATE_LAST_CHILD(cur)
1.28 daniel 1853: free(cur->content);
1854: cur->content = NULL;
1.32 daniel 1855: last = cur->last;
1.28 daniel 1856: }
1857: }
1.31 daniel 1858: new = xmlNewTextLen(content, len);
1.28 daniel 1859: if (new != NULL) {
1860: xmlAddChild(cur, new);
1.32 daniel 1861: if ((last != NULL) && (last->next == new)) {
1.28 daniel 1862: xmlTextMerge(last, new);
1.32 daniel 1863: }
1.28 daniel 1864: }
1865: break;
1866: }
1867: case XML_ATTRIBUTE_NODE:
1868: break;
1869: case XML_TEXT_NODE:
1870: case XML_CDATA_SECTION_NODE:
1871: case XML_ENTITY_REF_NODE:
1872: case XML_ENTITY_NODE:
1873: case XML_PI_NODE:
1874: case XML_COMMENT_NODE:
1875: if (content != NULL)
1876: cur->content = xmlStrncat(cur->content, content, len);
1877: case XML_DOCUMENT_NODE:
1878: case XML_DOCUMENT_TYPE_NODE:
1879: break;
1880: case XML_NOTATION_NODE:
1881: if (content != NULL)
1882: cur->content = xmlStrncat(cur->content, content, len);
1883: break;
1884: }
1.21 daniel 1885: }
1886:
1.23 daniel 1887: /**
1.28 daniel 1888: * xmlNodeAddContent:
1.23 daniel 1889: * @cur: the node being modified
1890: * @content: extra content
1891: *
1892: * Append the extra substring to the node content.
1.21 daniel 1893: */
1.28 daniel 1894: void
1895: xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1896: int len;
1897:
1.21 daniel 1898: if (cur == NULL) {
1899: fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1900: return;
1901: }
1.28 daniel 1902: if (content == NULL) return;
1903: len = xmlStrlen(content);
1904: xmlNodeAddContentLen(cur, content, len);
1905: }
1906:
1907: /**
1908: * xmlTextMerge:
1909: * @first: the first text node
1910: * @second: the second text node being merged
1911: *
1912: * Merge two text nodes into one
1913: * Return values: the first text node augmented
1914: */
1915: xmlNodePtr
1916: xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1917: if (first == NULL) return(second);
1918: if (second == NULL) return(first);
1919: if (first->type != XML_TEXT_NODE) return(first);
1920: if (second->type != XML_TEXT_NODE) return(first);
1921: xmlNodeAddContent(first, second->content);
1922: xmlUnlinkNode(second);
1923: xmlFreeNode(second);
1924: return(first);
1.21 daniel 1925: }
1926:
1.23 daniel 1927: /**
1928: * xmlSearchNs:
1929: * @doc: the document
1930: * @node: the current node
1931: * @nameSpace: the namespace string
1932: *
1.16 daniel 1933: * Search a Ns registered under a given name space for a document.
1.23 daniel 1934: * recurse on the parents until it finds the defined namespace
1935: * or return NULL otherwise.
1936: * @nameSpace can be NULL, this is a search for the default namespace.
1937: * return values: the namespace pointer or NULL.
1.3 veillard 1938: */
1.28 daniel 1939: xmlNsPtr
1940: xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
1.16 daniel 1941: xmlNsPtr cur;
1.3 veillard 1942:
1.19 daniel 1943: while (node != NULL) {
1944: cur = node->nsDef;
1945: while (cur != NULL) {
1946: if ((cur->prefix == NULL) && (nameSpace == NULL))
1947: return(cur);
1948: if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1949: (!xmlStrcmp(cur->prefix, nameSpace)))
1950: return(cur);
1951: cur = cur->next;
1952: }
1953: node = node->parent;
1954: }
1955: if (doc != NULL) {
1956: cur = doc->oldNs;
1957: while (cur != NULL) {
1958: if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1959: (!xmlStrcmp(cur->prefix, nameSpace)))
1960: return(cur);
1961: cur = cur->next;
1962: }
1963: }
1964: return(NULL);
1965: }
1.3 veillard 1966:
1.23 daniel 1967: /**
1968: * xmlSearchNsByHref:
1969: * @doc: the document
1970: * @node: the current node
1971: * @href: the namespace value
1972: *
1973: * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1974: * the defined namespace or return NULL otherwise.
1975: * return values: the namespace pointer or NULL.
1.19 daniel 1976: */
1.28 daniel 1977: xmlNsPtr
1978: xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
1.19 daniel 1979: xmlNsPtr cur;
1980:
1981: while (node != NULL) {
1982: cur = node->nsDef;
1983: while (cur != NULL) {
1984: if ((cur->href != NULL) && (href != NULL) &&
1985: (!xmlStrcmp(cur->href, href)))
1986: return(cur);
1987: cur = cur->next;
1988: }
1989: node = node->parent;
1990: }
1991: if (doc != NULL) {
1992: cur = doc->oldNs;
1993: while (cur != NULL) {
1994: if ((cur->href != NULL) && (href != NULL) &&
1995: (!xmlStrcmp(cur->href, href)))
1996: return(cur);
1997: cur = cur->next;
1998: }
1.3 veillard 1999: }
2000: return(NULL);
2001: }
2002:
1.23 daniel 2003: /**
2004: * xmlGetProp:
2005: * @node: the node
2006: * @name: the attribute name
2007: *
2008: * Search and get the value of an attribute associated to a node
2009: * This does the entity substitution.
2010: * return values: the attribute value or NULL if not found.
1.9 veillard 2011: */
1.31 daniel 2012: CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
1.20 daniel 2013: xmlAttrPtr prop = node->properties;
1.9 veillard 2014:
2015: while (prop != NULL) {
1.34 ! daniel 2016: if (!xmlStrcmp(prop->name, name)) {
! 2017: CHAR *ret;
! 2018:
! 2019: ret = xmlNodeListGetString(node->doc, prop->val, 1);
! 2020: if (ret == NULL) return(xmlStrdup(""));
! 2021: return(ret);
! 2022: }
1.9 veillard 2023: prop = prop->next;
2024: }
1.10 veillard 2025: return(NULL);
1.13 daniel 2026: }
2027:
1.23 daniel 2028: /**
2029: * xmlSetProp:
2030: * @node: the node
2031: * @name: the attribute name
2032: * @value: the attribute value
2033: *
2034: * Set (or reset) an attribute carried by a node.
2035: * return values: the attribute pointer.
1.13 daniel 2036: */
1.28 daniel 2037: xmlAttrPtr
2038: xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
1.20 daniel 2039: xmlAttrPtr prop = node->properties;
1.13 daniel 2040:
2041: while (prop != NULL) {
2042: if (!xmlStrcmp(prop->name, name)) {
1.23 daniel 2043: if (prop->val != NULL)
2044: xmlFreeNode(prop->val);
2045: prop->val = NULL;
1.13 daniel 2046: if (value != NULL)
1.24 daniel 2047: prop->val = xmlStringGetNodeList(node->doc, value);
1.13 daniel 2048: return(prop);
2049: }
2050: prop = prop->next;
2051: }
2052: prop = xmlNewProp(node, name, value);
2053: return(prop);
1.9 veillard 2054: }
2055:
1.23 daniel 2056: /**
2057: * xmlNodeIsText:
2058: * @node: the node
2059: *
2060: * Is this node a Text node ?
2061: * return values: 1 yes, 0 no
1.21 daniel 2062: */
1.28 daniel 2063: int
2064: xmlNodeIsText(xmlNodePtr node) {
1.21 daniel 2065: if (node == NULL) return(0);
2066:
1.23 daniel 2067: if (node->type == XML_TEXT_NODE) return(1);
1.21 daniel 2068: return(0);
2069: }
2070:
1.23 daniel 2071: /**
2072: * xmlNodeIsText:
2073: * @node: the node
2074: * @content: the content
2075: * @len: @content lenght
2076: *
2077: * Concat the given string at the end of the existing node content
1.21 daniel 2078: */
1.23 daniel 2079:
1.28 daniel 2080: void
2081: xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
1.21 daniel 2082: if (node == NULL) return;
2083:
1.23 daniel 2084: if (node->type != XML_TEXT_NODE) {
1.21 daniel 2085: fprintf(stderr, "xmlTextConcat: node is not text\n");
2086: return;
2087: }
2088: node->content = xmlStrncat(node->content, content, len);
2089: }
2090:
1.1 veillard 2091: /************************************************************************
2092: * *
1.8 veillard 2093: * Output : to a FILE or in memory *
1.1 veillard 2094: * *
2095: ************************************************************************/
2096:
1.8 veillard 2097: static CHAR *buffer = NULL;
2098: static int buffer_index = 0;
2099: static int buffer_size = 0;
2100:
1.23 daniel 2101: /**
2102: * xmlBufferWriteCHAR:
2103: * @string: the string to add
2104: *
2105: * routine which manage and grows an output buffer. This one add
2106: * CHARs at the end of the array.
2107: */
1.28 daniel 2108: void
2109: xmlBufferWriteCHAR(const CHAR *string) {
1.8 veillard 2110: const CHAR *cur;
2111:
2112: if (buffer == NULL) {
2113: buffer_size = 50000;
2114: buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2115: if (buffer == NULL) {
2116: fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2117: exit(1);
2118: }
2119: }
2120:
2121: if (string == NULL) return;
2122: for (cur = string;*cur != 0;cur++) {
2123: if (buffer_index + 10 >= buffer_size) {
2124: buffer_size *= 2;
2125: buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2126: if (buffer == NULL) {
2127: fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2128: exit(1);
2129: }
2130: }
2131: buffer[buffer_index++] = *cur;
2132: }
2133: buffer[buffer_index] = 0;
2134: }
2135:
1.23 daniel 2136: /**
2137: * xmlBufferWriteChar:
2138: * @string: the string to add
2139: *
2140: * routine which manage and grows an output buffer. This one add
2141: * C chars at the end of the array.
2142: */
1.28 daniel 2143: void
2144: xmlBufferWriteChar(const char *string) {
1.21 daniel 2145: const char *cur;
1.8 veillard 2146:
2147: if (buffer == NULL) {
2148: buffer_size = 50000;
2149: buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2150: if (buffer == NULL) {
2151: fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2152: exit(1);
2153: }
2154: }
2155:
2156: if (string == NULL) return;
2157: for (cur = string;*cur != 0;cur++) {
2158: if (buffer_index + 10 >= buffer_size) {
2159: buffer_size *= 2;
2160: buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2161: if (buffer == NULL) {
2162: fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2163: exit(1);
2164: }
2165: }
2166: buffer[buffer_index++] = *cur;
2167: }
2168: buffer[buffer_index] = 0;
2169: }
2170:
1.23 daniel 2171: /**
2172: * xmlGlobalNsDump:
2173: * @cur: a namespace
2174: *
2175: * Dump a global Namespace, this is the old version based on PIs.
1.1 veillard 2176: */
1.28 daniel 2177: static void
2178: xmlGlobalNsDump(xmlNsPtr cur) {
1.1 veillard 2179: if (cur == NULL) {
1.19 daniel 2180: fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
1.1 veillard 2181: return;
2182: }
1.19 daniel 2183: if (cur->type == XML_GLOBAL_NAMESPACE) {
1.12 daniel 2184: xmlBufferWriteChar("<?namespace");
2185: if (cur->href != NULL) {
2186: xmlBufferWriteChar(" href=\"");
2187: xmlBufferWriteCHAR(cur->href);
2188: xmlBufferWriteChar("\"");
2189: }
1.16 daniel 2190: if (cur->prefix != NULL) {
1.12 daniel 2191: xmlBufferWriteChar(" AS=\"");
1.16 daniel 2192: xmlBufferWriteCHAR(cur->prefix);
1.12 daniel 2193: xmlBufferWriteChar("\"");
2194: }
2195: xmlBufferWriteChar("?>\n");
1.19 daniel 2196: }
2197: }
2198:
1.23 daniel 2199: /**
2200: * xmlGlobalNsListDump:
2201: * @cur: the first namespace
2202: *
2203: * Dump a list of global Namespace, this is the old version based on PIs.
1.19 daniel 2204: */
1.28 daniel 2205: static void
2206: xmlGlobalNsListDump(xmlNsPtr cur) {
1.19 daniel 2207: while (cur != NULL) {
2208: xmlGlobalNsDump(cur);
2209: cur = cur->next;
2210: }
2211: }
2212:
1.23 daniel 2213: /**
2214: * xmlNsDump:
2215: * @cur: a namespace
2216: *
1.19 daniel 2217: * Dump a local Namespace definition.
1.23 daniel 2218: * Should be called in the context of attributes dumps.
1.19 daniel 2219: */
1.28 daniel 2220: static void
2221: xmlNsDump(xmlNsPtr cur) {
1.19 daniel 2222: if (cur == NULL) {
2223: fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2224: return;
2225: }
2226: if (cur->type == XML_LOCAL_NAMESPACE) {
2227: /* Within the context of an element attributes */
1.16 daniel 2228: if (cur->prefix != NULL) {
1.19 daniel 2229: xmlBufferWriteChar(" xmlns:");
1.16 daniel 2230: xmlBufferWriteCHAR(cur->prefix);
1.19 daniel 2231: } else
2232: xmlBufferWriteChar(" xmlns");
2233: xmlBufferWriteChar("=\"");
2234: xmlBufferWriteCHAR(cur->href);
2235: xmlBufferWriteChar("\"");
2236: }
2237: }
2238:
1.23 daniel 2239: /**
2240: * xmlNsListDump:
2241: * @cur: the first namespace
2242: *
2243: * Dump a list of local Namespace definitions.
2244: * Should be called in the context of attributes dumps.
1.19 daniel 2245: */
1.28 daniel 2246: static void
2247: xmlNsListDump(xmlNsPtr cur) {
1.19 daniel 2248: while (cur != NULL) {
2249: xmlNsDump(cur);
2250: cur = cur->next;
1.8 veillard 2251: }
1.1 veillard 2252: }
2253:
1.23 daniel 2254: /**
2255: * xmlDtdDump:
2256: * @doc: the document
2257: *
2258: * Dump the XML document DTD, if any.
1.17 daniel 2259: */
1.28 daniel 2260: static void
2261: xmlDtdDump(xmlDocPtr doc) {
1.31 daniel 2262: xmlDtdPtr cur = doc->intSubset;
1.21 daniel 2263:
1.17 daniel 2264: if (cur == NULL) {
1.31 daniel 2265: fprintf(stderr, "xmlDtdDump : no internal subset\n");
1.17 daniel 2266: return;
2267: }
2268: xmlBufferWriteChar("<!DOCTYPE ");
2269: xmlBufferWriteCHAR(cur->name);
2270: if (cur->ExternalID != NULL) {
2271: xmlBufferWriteChar(" PUBLIC \"");
2272: xmlBufferWriteCHAR(cur->ExternalID);
2273: xmlBufferWriteChar("\" \"");
2274: xmlBufferWriteCHAR(cur->SystemID);
2275: xmlBufferWriteChar("\"");
2276: } else if (cur->SystemID != NULL) {
2277: xmlBufferWriteChar(" SYSTEM \"");
2278: xmlBufferWriteCHAR(cur->SystemID);
2279: xmlBufferWriteChar("\"");
2280: }
1.34 ! daniel 2281: if ((cur->entities == NULL) && (cur->elements == NULL) &&
! 2282: (cur->attributes == NULL)) {
1.21 daniel 2283: xmlBufferWriteChar(">\n");
2284: return;
2285: }
2286: xmlBufferWriteChar(" [\n");
2287: if (cur->entities != NULL)
1.18 daniel 2288: xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1.33 daniel 2289: if (cur->elements != NULL)
2290: xmlDumpElementTable((xmlElementTablePtr) cur->elements);
1.34 ! daniel 2291: if (cur->attributes != NULL)
! 2292: xmlDumpAttributeTable((xmlAttributeTablePtr) cur->attributes);
1.21 daniel 2293: xmlBufferWriteChar("]");
2294:
1.17 daniel 2295: /* TODO !!! a lot more things to dump ... */
2296: xmlBufferWriteChar(">\n");
2297: }
2298:
1.23 daniel 2299: /**
2300: * xmlAttrDump:
2301: * @doc: the document
2302: * @cur: the attribute pointer
2303: *
2304: * Dump an XML attribute
1.1 veillard 2305: */
1.28 daniel 2306: static void
2307: xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
1.23 daniel 2308: CHAR *value;
1.1 veillard 2309:
2310: if (cur == NULL) {
1.20 daniel 2311: fprintf(stderr, "xmlAttrDump : property == NULL\n");
1.1 veillard 2312: return;
2313: }
1.8 veillard 2314: xmlBufferWriteChar(" ");
2315: xmlBufferWriteCHAR(cur->name);
1.24 daniel 2316: value = xmlNodeListGetString(doc, cur->val, 0);
1.23 daniel 2317: if (value) {
1.8 veillard 2318: xmlBufferWriteChar("=\"");
1.23 daniel 2319: xmlBufferWriteCHAR(value);
1.8 veillard 2320: xmlBufferWriteChar("\"");
1.23 daniel 2321: free(value);
1.34 ! daniel 2322: } else {
! 2323: xmlBufferWriteChar("=\"\"");
1.3 veillard 2324: }
1.8 veillard 2325: }
2326:
1.23 daniel 2327: /**
2328: * xmlAttrListDump:
2329: * @doc: the document
2330: * @cur: the first attribute pointer
2331: *
2332: * Dump a list of XML attributes
1.8 veillard 2333: */
1.28 daniel 2334: static void
2335: xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
1.8 veillard 2336: if (cur == NULL) {
1.20 daniel 2337: fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1.1 veillard 2338: return;
2339: }
1.8 veillard 2340: while (cur != NULL) {
1.20 daniel 2341: xmlAttrDump(doc, cur);
1.8 veillard 2342: cur = cur->next;
1.1 veillard 2343: }
2344: }
2345:
2346:
1.28 daniel 2347: static void
2348: xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
1.23 daniel 2349: /**
2350: * xmlNodeListDump:
2351: * @doc: the document
2352: * @cur: the first node
2353: * @level: the imbrication level for indenting
2354: *
2355: * Dump an XML node list, recursive behaviour,children are printed too.
2356: */
1.28 daniel 2357: static void
2358: xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1.25 daniel 2359: int needIndent = 0, i;
2360:
1.1 veillard 2361: if (cur == NULL) {
1.8 veillard 2362: fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1.1 veillard 2363: return;
2364: }
1.8 veillard 2365: while (cur != NULL) {
1.25 daniel 2366: if ((cur->type != XML_TEXT_NODE) &&
2367: (cur->type != XML_ENTITY_REF_NODE)) {
2368: if (!needIndent) {
2369: needIndent = 1;
2370: xmlBufferWriteChar("\n");
2371: }
2372: }
1.8 veillard 2373: xmlNodeDump(doc, cur, level);
2374: cur = cur->next;
1.3 veillard 2375: }
1.25 daniel 2376: if ((xmlIndentTreeOutput) && (needIndent))
2377: for (i = 1;i < level;i++)
2378: xmlBufferWriteChar(" ");
1.1 veillard 2379: }
2380:
1.23 daniel 2381: /**
1.25 daniel 2382: * xmlNodeDump:
1.23 daniel 2383: * @doc: the document
2384: * @cur: the current node
2385: * @level: the imbrication level for indenting
2386: *
2387: * Dump an XML node, recursive behaviour,children are printed too.
1.1 veillard 2388: */
1.28 daniel 2389: static void
2390: xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1.8 veillard 2391: int i;
2392:
1.1 veillard 2393: if (cur == NULL) {
1.8 veillard 2394: fprintf(stderr, "xmlNodeDump : node == NULL\n");
2395: return;
2396: }
1.23 daniel 2397: if (cur->type == XML_TEXT_NODE) {
1.8 veillard 2398: if (cur->content != NULL)
2399: xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1.14 daniel 2400: return;
2401: }
1.23 daniel 2402: if (cur->type == XML_COMMENT_NODE) {
1.14 daniel 2403: if (cur->content != NULL) {
2404: xmlBufferWriteChar("<!--");
1.18 daniel 2405: xmlBufferWriteCHAR(cur->content);
1.14 daniel 2406: xmlBufferWriteChar("-->");
2407: }
1.8 veillard 2408: return;
2409: }
1.23 daniel 2410: if (cur->type == XML_ENTITY_REF_NODE) {
2411: xmlBufferWriteChar("&");
2412: xmlBufferWriteCHAR(cur->name);
2413: xmlBufferWriteChar(";");
2414: return;
2415: }
1.21 daniel 2416: if (xmlIndentTreeOutput)
2417: for (i = 0;i < level;i++)
2418: xmlBufferWriteChar(" ");
1.8 veillard 2419:
2420: xmlBufferWriteChar("<");
1.16 daniel 2421: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2422: xmlBufferWriteCHAR(cur->ns->prefix);
1.8 veillard 2423: xmlBufferWriteChar(":");
2424: }
2425:
2426: xmlBufferWriteCHAR(cur->name);
1.19 daniel 2427: if (cur->nsDef)
2428: xmlNsListDump(cur->nsDef);
1.8 veillard 2429: if (cur->properties != NULL)
1.20 daniel 2430: xmlAttrListDump(doc, cur->properties);
1.8 veillard 2431:
2432: if ((cur->content == NULL) && (cur->childs == NULL)) {
2433: xmlBufferWriteChar("/>\n");
1.1 veillard 2434: return;
2435: }
1.8 veillard 2436: xmlBufferWriteChar(">");
2437: if (cur->content != NULL)
2438: xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2439: if (cur->childs != NULL) {
2440: xmlNodeListDump(doc, cur->childs, level + 1);
2441: }
2442: xmlBufferWriteChar("</");
1.16 daniel 2443: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2444: xmlBufferWriteCHAR(cur->ns->prefix);
1.8 veillard 2445: xmlBufferWriteChar(":");
1.1 veillard 2446: }
1.8 veillard 2447:
2448: xmlBufferWriteCHAR(cur->name);
2449: xmlBufferWriteChar(">\n");
1.1 veillard 2450: }
2451:
1.23 daniel 2452: /**
2453: * xmlDocContentDump:
2454: * @cur: the document
2455: *
2456: * Dump an XML document.
1.1 veillard 2457: */
1.28 daniel 2458: static void
2459: xmlDocContentDump(xmlDocPtr cur) {
1.12 daniel 2460: if (oldXMLWDcompatibility)
2461: xmlBufferWriteChar("<?XML version=\"");
2462: else
2463: xmlBufferWriteChar("<?xml version=\"");
1.8 veillard 2464: xmlBufferWriteCHAR(cur->version);
1.15 daniel 2465: xmlBufferWriteChar("\"");
2466: if (cur->encoding != NULL) {
2467: xmlBufferWriteChar(" encoding=\"");
2468: xmlBufferWriteCHAR(cur->encoding);
2469: xmlBufferWriteChar("\"");
2470: }
2471: switch (cur->standalone) {
2472: case 0:
2473: xmlBufferWriteChar(" standalone=\"no\"");
2474: break;
2475: case 1:
2476: xmlBufferWriteChar(" standalone=\"yes\"");
2477: break;
2478: }
2479: xmlBufferWriteChar("?>\n");
1.31 daniel 2480: if (cur->intSubset != NULL)
1.21 daniel 2481: xmlDtdDump(cur);
1.19 daniel 2482: if (cur->root != NULL) {
2483: /* global namespace definitions, the old way */
2484: if (oldXMLWDcompatibility)
2485: xmlGlobalNsListDump(cur->oldNs);
2486: else
2487: xmlUpgradeOldNs(cur);
1.8 veillard 2488: xmlNodeDump(cur, cur->root, 0);
1.19 daniel 2489: }
2490: }
2491:
1.23 daniel 2492: /**
2493: * xmlDocDumpMemory:
2494: * @cur: the document
2495: * @mem: OUT: the memory pointer
2496: * @size: OUT: the memory lenght
2497: *
2498: * Dump an XML document in memory and return the CHAR * and it's size.
2499: * It's up to the caller to free the memory.
1.19 daniel 2500: */
1.28 daniel 2501: void
2502: xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
1.19 daniel 2503: if (cur == NULL) {
1.31 daniel 2504: #ifdef DEBUG_TREE
2505: fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2506: #endif
1.19 daniel 2507: *mem = NULL;
2508: *size = 0;
2509: return;
2510: }
2511: buffer_index = 0;
2512: xmlDocContentDump(cur);
1.8 veillard 2513:
2514: *mem = buffer;
2515: *size = buffer_index;
1.1 veillard 2516: }
2517:
1.23 daniel 2518: /**
2519: * xmlGetDocCompressMode:
2520: * @doc: the document
2521: *
2522: * get the compression ratio for a document, ZLIB based
2523: * return values: 0 (uncompressed) to 9 (max compression)
2524: */
1.28 daniel 2525: int
2526: xmlGetDocCompressMode (xmlDocPtr doc) {
1.23 daniel 2527: if (doc == NULL) return(-1);
2528: return(doc->compression);
2529: }
2530:
2531: /**
2532: * xmlSetDocCompressMode:
2533: * @doc: the document
2534: * @mode: the compression ratio
2535: *
2536: * set the compression ratio for a document, ZLIB based
2537: * Correct values: 0 (uncompressed) to 9 (max compression)
2538: */
1.28 daniel 2539: void
2540: xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1.23 daniel 2541: if (doc == NULL) return;
2542: if (mode < 0) doc->compression = 0;
2543: else if (mode > 9) doc->compression = 9;
2544: else doc->compression = mode;
2545: }
2546:
2547: /**
2548: * xmlGetCompressMode:
2549: *
2550: * get the default compression mode used, ZLIB based.
2551: * return values: 0 (uncompressed) to 9 (max compression)
2552: */
1.28 daniel 2553: int
2554: xmlGetCompressMode(void) {
1.23 daniel 2555: return(xmlCompressMode);
2556: }
2557:
2558: /**
2559: * xmlSetCompressMode:
2560: * @mode: the compression ratio
2561: *
2562: * set the default compression mode used, ZLIB based
2563: * Correct values: 0 (uncompressed) to 9 (max compression)
1.1 veillard 2564: */
1.28 daniel 2565: void
2566: xmlSetCompressMode(int mode) {
1.23 daniel 2567: if (mode < 0) xmlCompressMode = 0;
2568: else if (mode > 9) xmlCompressMode = 9;
2569: else xmlCompressMode = mode;
2570: }
1.1 veillard 2571:
1.23 daniel 2572: /**
2573: * xmlDocDump:
2574: * @f: the FILE*
2575: * @cur: the document
2576: *
2577: * Dump an XML document to an open FILE.
2578: */
1.28 daniel 2579: void
2580: xmlDocDump(FILE *f, xmlDocPtr cur) {
1.1 veillard 2581: if (cur == NULL) {
1.31 daniel 2582: #ifdef DEBUG_TREE
1.1 veillard 2583: fprintf(stderr, "xmlDocDump : document == NULL\n");
1.31 daniel 2584: #endif
1.1 veillard 2585: return;
2586: }
1.8 veillard 2587: buffer_index = 0;
1.19 daniel 2588: xmlDocContentDump(cur);
1.8 veillard 2589:
2590: fwrite(buffer, sizeof(CHAR), buffer_index, f);
1.23 daniel 2591: }
2592:
2593: /**
2594: * xmlSaveFile:
2595: * @filename: the filename
2596: * @cur: the document
2597: *
2598: * Dump an XML document to a file. Will use compression if
2599: * compiled in and enabled.
2600: * returns: the number of file written or -1 in case of failure.
2601: */
1.28 daniel 2602: int
2603: xmlSaveFile(const char *filename, xmlDocPtr cur) {
1.23 daniel 2604: #ifdef HAVE_ZLIB_H
2605: gzFile zoutput = NULL;
2606: char mode[15];
2607: #endif
1.24 daniel 2608: FILE *output = NULL;
1.23 daniel 2609: int ret;
2610:
2611: #ifdef HAVE_ZLIB_H
2612: if ((cur->compression > 0) && (cur->compression <= 9)) {
2613: sprintf(mode, "w%d", cur->compression);
2614: zoutput = gzopen(filename, mode);
2615: }
2616: if (zoutput == NULL) {
2617: #endif
2618: output = fopen(filename, "w");
2619: if (output == NULL) return(-1);
2620: #ifdef HAVE_ZLIB_H
2621: }
2622: #endif
2623:
2624: /*
2625: * save the content to a temp buffer.
2626: */
2627: buffer_index = 0;
2628: xmlDocContentDump(cur);
2629:
2630: #ifdef HAVE_ZLIB_H
2631: if (zoutput != NULL) {
2632: ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2633: gzclose(zoutput);
2634: return(ret);
2635: }
2636: #endif
2637: ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2638: fclose(output);
2639: return(ret * sizeof(CHAR));
1.1 veillard 2640: }
2641:
Webmaster