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