ReactOS  0.4.13-dev-443-g10f00f8
tree.c
Go to the documentation of this file.
1 /*
2  * tree.c : implementation of access function for an XML tree.
3  *
4  * References:
5  * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  *
11  */
12 
13 /* To avoid EBCDIC trouble when parsing on zOS */
14 #if defined(__MVS__)
15 #pragma convert("ISO8859-1")
16 #endif
17 
18 #define IN_LIBXML
19 #include "libxml.h"
20 
21 #include <string.h> /* for memset() only ! */
22 #include <stddef.h>
23 #include <limits.h>
24 #ifdef HAVE_CTYPE_H
25 #include <ctype.h>
26 #endif
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #ifdef LIBXML_ZLIB_ENABLED
31 #include <zlib.h>
32 #endif
33 
34 #include <libxml/xmlmemory.h>
35 #include <libxml/tree.h>
36 #include <libxml/parser.h>
37 #include <libxml/uri.h>
38 #include <libxml/entities.h>
39 #include <libxml/valid.h>
40 #include <libxml/xmlerror.h>
41 #include <libxml/parserInternals.h>
42 #include <libxml/globals.h>
43 #ifdef LIBXML_HTML_ENABLED
44 #include <libxml/HTMLtree.h>
45 #endif
46 #ifdef LIBXML_DEBUG_ENABLED
47 #include <libxml/debugXML.h>
48 #endif
49 
50 #include "buf.h"
51 #include "save.h"
52 
54 
55 /************************************************************************
56  * *
57  * Forward declarations *
58  * *
59  ************************************************************************/
60 
61 static xmlNsPtr
63 
64 static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
65 
66 /************************************************************************
67  * *
68  * Tree memory error handler *
69  * *
70  ************************************************************************/
77 static void
78 xmlTreeErrMemory(const char *extra)
79 {
80  __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
81 }
82 
90 static void
91 xmlTreeErr(int code, xmlNodePtr node, const char *extra)
92 {
93  const char *msg = NULL;
94 
95  switch(code) {
97  msg = "invalid hexadecimal character value\n";
98  break;
100  msg = "invalid decimal character value\n";
101  break;
103  msg = "unterminated entity reference %15s\n";
104  break;
105  case XML_TREE_NOT_UTF8:
106  msg = "string is not in UTF-8\n";
107  break;
108  default:
109  msg = "unexpected error number\n";
110  }
111  __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
112 }
113 
114 /************************************************************************
115  * *
116  * A few static variables and macros *
117  * *
118  ************************************************************************/
119 /* #undef xmlStringText */
120 const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
121 /* #undef xmlStringTextNoenc */
122 const xmlChar xmlStringTextNoenc[] =
123  { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
124 /* #undef xmlStringComment */
125 const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
126 
127 static int xmlCompressMode = 0;
128 static int xmlCheckDTD = 1;
129 
130 #define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
131  xmlNodePtr ulccur = (n)->children; \
132  if (ulccur == NULL) { \
133  (n)->last = NULL; \
134  } else { \
135  while (ulccur->next != NULL) { \
136  ulccur->parent = (n); \
137  ulccur = ulccur->next; \
138  } \
139  ulccur->parent = (n); \
140  (n)->last = ulccur; \
141 }}
142 
143 #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
144  (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
145 
146 /* #define DEBUG_BUFFER */
147 /* #define DEBUG_TREE */
148 
149 /************************************************************************
150  * *
151  * Functions to move to entities.c once the *
152  * API freeze is smoothen and they can be made public. *
153  * *
154  ************************************************************************/
155 #include <libxml/hash.h>
156 
157 #ifdef LIBXML_TREE_ENABLED
158 
168 static xmlEntityPtr
169 xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
171 
172  if((dtd != NULL) && (dtd->entities != NULL)) {
174  return((xmlEntityPtr) xmlHashLookup(table, name));
175  /* return(xmlGetEntityFromTable(table, name)); */
176  }
177  return(NULL);
178 }
189 static xmlEntityPtr
190 xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
192 
193  if ((dtd != NULL) && (dtd->pentities != NULL)) {
195  return((xmlEntityPtr) xmlHashLookup(table, name));
196  /* return(xmlGetEntityFromTable(table, name)); */
197  }
198  return(NULL);
199 }
200 #endif /* LIBXML_TREE_ENABLED */
201 
202 /************************************************************************
203  * *
204  * QName handling helper *
205  * *
206  ************************************************************************/
207 
222 xmlChar *
223 xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
224  xmlChar *memory, int len) {
225  int lenn, lenp;
226  xmlChar *ret;
227 
228  if (ncname == NULL) return(NULL);
229  if (prefix == NULL) return((xmlChar *) ncname);
230 
231  lenn = strlen((char *) ncname);
232  lenp = strlen((char *) prefix);
233 
234  if ((memory == NULL) || (len < lenn + lenp + 2)) {
235  ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
236  if (ret == NULL) {
237  xmlTreeErrMemory("building QName");
238  return(NULL);
239  }
240  } else {
241  ret = memory;
242  }
243  memcpy(&ret[0], prefix, lenp);
244  ret[lenp] = ':';
245  memcpy(&ret[lenp + 1], ncname, lenn);
246  ret[lenn + lenp + 1] = 0;
247  return(ret);
248 }
249 
267 xmlChar *
268 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
269  int len = 0;
270  xmlChar *ret = NULL;
271 
272  if (prefix == NULL) return(NULL);
273  *prefix = NULL;
274  if (name == NULL) return(NULL);
275 
276 #ifndef XML_XML_NAMESPACE
277  /* xml: prefix is not really a namespace */
278  if ((name[0] == 'x') && (name[1] == 'm') &&
279  (name[2] == 'l') && (name[3] == ':'))
280  return(NULL);
281 #endif
282 
283  /* nasty but valid */
284  if (name[0] == ':')
285  return(NULL);
286 
287  /*
288  * we are not trying to validate but just to cut, and yes it will
289  * work even if this is as set of UTF-8 encoded chars
290  */
291  while ((name[len] != 0) && (name[len] != ':'))
292  len++;
293 
294  if (name[len] == 0)
295  return(NULL);
296 
297  *prefix = xmlStrndup(name, len);
298  if (*prefix == NULL) {
299  xmlTreeErrMemory("QName split");
300  return(NULL);
301  }
302  ret = xmlStrdup(&name[len + 1]);
303  if (ret == NULL) {
304  xmlTreeErrMemory("QName split");
305  if (*prefix != NULL) {
306  xmlFree(*prefix);
307  *prefix = NULL;
308  }
309  return(NULL);
310  }
311 
312  return(ret);
313 }
314 
327 const xmlChar *
328 xmlSplitQName3(const xmlChar *name, int *len) {
329  int l = 0;
330 
331  if (name == NULL) return(NULL);
332  if (len == NULL) return(NULL);
333 
334  /* nasty but valid */
335  if (name[0] == ':')
336  return(NULL);
337 
338  /*
339  * we are not trying to validate but just to cut, and yes it will
340  * work even if this is as set of UTF-8 encoded chars
341  */
342  while ((name[l] != 0) && (name[l] != ':'))
343  l++;
344 
345  if (name[l] == 0)
346  return(NULL);
347 
348  *len = l;
349 
350  return(&name[l+1]);
351 }
352 
353 /************************************************************************
354  * *
355  * Check Name, NCName and QName strings *
356  * *
357  ************************************************************************/
358 
359 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
360 
361 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
362 
372 int
373 xmlValidateNCName(const xmlChar *value, int space) {
374  const xmlChar *cur = value;
375  int c,l;
376 
377  if (value == NULL)
378  return(-1);
379 
380  /*
381  * First quick algorithm for ASCII range
382  */
383  if (space)
384  while (IS_BLANK_CH(*cur)) cur++;
385  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
386  (*cur == '_'))
387  cur++;
388  else
389  goto try_complex;
390  while (((*cur >= 'a') && (*cur <= 'z')) ||
391  ((*cur >= 'A') && (*cur <= 'Z')) ||
392  ((*cur >= '0') && (*cur <= '9')) ||
393  (*cur == '_') || (*cur == '-') || (*cur == '.'))
394  cur++;
395  if (space)
396  while (IS_BLANK_CH(*cur)) cur++;
397  if (*cur == 0)
398  return(0);
399 
400 try_complex:
401  /*
402  * Second check for chars outside the ASCII range
403  */
404  cur = value;
405  c = CUR_SCHAR(cur, l);
406  if (space) {
407  while (IS_BLANK(c)) {
408  cur += l;
409  c = CUR_SCHAR(cur, l);
410  }
411  }
412  if ((!IS_LETTER(c)) && (c != '_'))
413  return(1);
414  cur += l;
415  c = CUR_SCHAR(cur, l);
416  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
417  (c == '-') || (c == '_') || IS_COMBINING(c) ||
418  IS_EXTENDER(c)) {
419  cur += l;
420  c = CUR_SCHAR(cur, l);
421  }
422  if (space) {
423  while (IS_BLANK(c)) {
424  cur += l;
425  c = CUR_SCHAR(cur, l);
426  }
427  }
428  if (c != 0)
429  return(1);
430 
431  return(0);
432 }
433 #endif
434 
435 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
436 
446 int
447 xmlValidateQName(const xmlChar *value, int space) {
448  const xmlChar *cur = value;
449  int c,l;
450 
451  if (value == NULL)
452  return(-1);
453  /*
454  * First quick algorithm for ASCII range
455  */
456  if (space)
457  while (IS_BLANK_CH(*cur)) cur++;
458  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
459  (*cur == '_'))
460  cur++;
461  else
462  goto try_complex;
463  while (((*cur >= 'a') && (*cur <= 'z')) ||
464  ((*cur >= 'A') && (*cur <= 'Z')) ||
465  ((*cur >= '0') && (*cur <= '9')) ||
466  (*cur == '_') || (*cur == '-') || (*cur == '.'))
467  cur++;
468  if (*cur == ':') {
469  cur++;
470  if (((*cur >= 'a') && (*cur <= 'z')) ||
471  ((*cur >= 'A') && (*cur <= 'Z')) ||
472  (*cur == '_'))
473  cur++;
474  else
475  goto try_complex;
476  while (((*cur >= 'a') && (*cur <= 'z')) ||
477  ((*cur >= 'A') && (*cur <= 'Z')) ||
478  ((*cur >= '0') && (*cur <= '9')) ||
479  (*cur == '_') || (*cur == '-') || (*cur == '.'))
480  cur++;
481  }
482  if (space)
483  while (IS_BLANK_CH(*cur)) cur++;
484  if (*cur == 0)
485  return(0);
486 
487 try_complex:
488  /*
489  * Second check for chars outside the ASCII range
490  */
491  cur = value;
492  c = CUR_SCHAR(cur, l);
493  if (space) {
494  while (IS_BLANK(c)) {
495  cur += l;
496  c = CUR_SCHAR(cur, l);
497  }
498  }
499  if ((!IS_LETTER(c)) && (c != '_'))
500  return(1);
501  cur += l;
502  c = CUR_SCHAR(cur, l);
503  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
504  (c == '-') || (c == '_') || IS_COMBINING(c) ||
505  IS_EXTENDER(c)) {
506  cur += l;
507  c = CUR_SCHAR(cur, l);
508  }
509  if (c == ':') {
510  cur += l;
511  c = CUR_SCHAR(cur, l);
512  if ((!IS_LETTER(c)) && (c != '_'))
513  return(1);
514  cur += l;
515  c = CUR_SCHAR(cur, l);
516  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
517  (c == '-') || (c == '_') || IS_COMBINING(c) ||
518  IS_EXTENDER(c)) {
519  cur += l;
520  c = CUR_SCHAR(cur, l);
521  }
522  }
523  if (space) {
524  while (IS_BLANK(c)) {
525  cur += l;
526  c = CUR_SCHAR(cur, l);
527  }
528  }
529  if (c != 0)
530  return(1);
531  return(0);
532 }
533 
544 int
545 xmlValidateName(const xmlChar *value, int space) {
546  const xmlChar *cur = value;
547  int c,l;
548 
549  if (value == NULL)
550  return(-1);
551  /*
552  * First quick algorithm for ASCII range
553  */
554  if (space)
555  while (IS_BLANK_CH(*cur)) cur++;
556  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
557  (*cur == '_') || (*cur == ':'))
558  cur++;
559  else
560  goto try_complex;
561  while (((*cur >= 'a') && (*cur <= 'z')) ||
562  ((*cur >= 'A') && (*cur <= 'Z')) ||
563  ((*cur >= '0') && (*cur <= '9')) ||
564  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
565  cur++;
566  if (space)
567  while (IS_BLANK_CH(*cur)) cur++;
568  if (*cur == 0)
569  return(0);
570 
571 try_complex:
572  /*
573  * Second check for chars outside the ASCII range
574  */
575  cur = value;
576  c = CUR_SCHAR(cur, l);
577  if (space) {
578  while (IS_BLANK(c)) {
579  cur += l;
580  c = CUR_SCHAR(cur, l);
581  }
582  }
583  if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
584  return(1);
585  cur += l;
586  c = CUR_SCHAR(cur, l);
587  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
588  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
589  cur += l;
590  c = CUR_SCHAR(cur, l);
591  }
592  if (space) {
593  while (IS_BLANK(c)) {
594  cur += l;
595  c = CUR_SCHAR(cur, l);
596  }
597  }
598  if (c != 0)
599  return(1);
600  return(0);
601 }
602 
613 int
614 xmlValidateNMToken(const xmlChar *value, int space) {
615  const xmlChar *cur = value;
616  int c,l;
617 
618  if (value == NULL)
619  return(-1);
620  /*
621  * First quick algorithm for ASCII range
622  */
623  if (space)
624  while (IS_BLANK_CH(*cur)) cur++;
625  if (((*cur >= 'a') && (*cur <= 'z')) ||
626  ((*cur >= 'A') && (*cur <= 'Z')) ||
627  ((*cur >= '0') && (*cur <= '9')) ||
628  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
629  cur++;
630  else
631  goto try_complex;
632  while (((*cur >= 'a') && (*cur <= 'z')) ||
633  ((*cur >= 'A') && (*cur <= 'Z')) ||
634  ((*cur >= '0') && (*cur <= '9')) ||
635  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
636  cur++;
637  if (space)
638  while (IS_BLANK_CH(*cur)) cur++;
639  if (*cur == 0)
640  return(0);
641 
642 try_complex:
643  /*
644  * Second check for chars outside the ASCII range
645  */
646  cur = value;
647  c = CUR_SCHAR(cur, l);
648  if (space) {
649  while (IS_BLANK(c)) {
650  cur += l;
651  c = CUR_SCHAR(cur, l);
652  }
653  }
654  if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
655  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
656  return(1);
657  cur += l;
658  c = CUR_SCHAR(cur, l);
659  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
660  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
661  cur += l;
662  c = CUR_SCHAR(cur, l);
663  }
664  if (space) {
665  while (IS_BLANK(c)) {
666  cur += l;
667  c = CUR_SCHAR(cur, l);
668  }
669  }
670  if (c != 0)
671  return(1);
672  return(0);
673 }
674 #endif /* LIBXML_TREE_ENABLED */
675 
676 /************************************************************************
677  * *
678  * Allocation and deallocation of basic structures *
679  * *
680  ************************************************************************/
681 
691 void
693  if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
697 }
698 
714  return(xmlBufferAllocScheme);
715 }
716 
733 xmlNsPtr
734 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
735  xmlNsPtr cur;
736 
737  if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
738  return(NULL);
739 
740  if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
741  /* xml namespace is predefined, no need to add it */
742  if (xmlStrEqual(href, XML_XML_NAMESPACE))
743  return(NULL);
744 
745  /*
746  * Problem, this is an attempt to bind xml prefix to a wrong
747  * namespace, which breaks
748  * Namespace constraint: Reserved Prefixes and Namespace Names
749  * from XML namespace. But documents authors may not care in
750  * their context so let's proceed.
751  */
752  }
753 
754  /*
755  * Allocate a new Namespace and fill the fields.
756  */
757  cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
758  if (cur == NULL) {
759  xmlTreeErrMemory("building namespace");
760  return(NULL);
761  }
762  memset(cur, 0, sizeof(xmlNs));
763  cur->type = XML_LOCAL_NAMESPACE;
764 
765  if (href != NULL)
766  cur->href = xmlStrdup(href);
767  if (prefix != NULL)
768  cur->prefix = xmlStrdup(prefix);
769 
770  /*
771  * Add it at the end to preserve parsing order ...
772  * and checks for existing use of the prefix
773  */
774  if (node != NULL) {
775  if (node->nsDef == NULL) {
776  node->nsDef = cur;
777  } else {
778  xmlNsPtr prev = node->nsDef;
779 
780  if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
781  (xmlStrEqual(prev->prefix, cur->prefix))) {
782  xmlFreeNs(cur);
783  return(NULL);
784  }
785  while (prev->next != NULL) {
786  prev = prev->next;
787  if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
788  (xmlStrEqual(prev->prefix, cur->prefix))) {
789  xmlFreeNs(cur);
790  return(NULL);
791  }
792  }
793  prev->next = cur;
794  }
795  }
796  return(cur);
797 }
798 
806 void
808  if (node == NULL) {
809 #ifdef DEBUG_TREE
811  "xmlSetNs: node == NULL\n");
812 #endif
813  return;
814  }
815  if ((node->type == XML_ELEMENT_NODE) ||
816  (node->type == XML_ATTRIBUTE_NODE))
817  node->ns = ns;
818 }
819 
826 void
827 xmlFreeNs(xmlNsPtr cur) {
828  if (cur == NULL) {
829 #ifdef DEBUG_TREE
831  "xmlFreeNs : ns == NULL\n");
832 #endif
833  return;
834  }
835  if (cur->href != NULL) xmlFree((char *) cur->href);
836  if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
837  xmlFree(cur);
838 }
839 
846 void
847 xmlFreeNsList(xmlNsPtr cur) {
848  xmlNsPtr next;
849  if (cur == NULL) {
850 #ifdef DEBUG_TREE
852  "xmlFreeNsList : ns == NULL\n");
853 #endif
854  return;
855  }
856  while (cur != NULL) {
857  next = cur->next;
858  xmlFreeNs(cur);
859  cur = next;
860  }
861 }
862 
875 xmlDtdPtr
876 xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
877  const xmlChar *ExternalID, const xmlChar *SystemID) {
878  xmlDtdPtr cur;
879 
880  if ((doc != NULL) && (doc->extSubset != NULL)) {
881 #ifdef DEBUG_TREE
883  "xmlNewDtd(%s): document %s already have a DTD %s\n",
884  /* !!! */ (char *) name, doc->name,
885  /* !!! */ (char *)doc->extSubset->name);
886 #endif
887  return(NULL);
888  }
889 
890  /*
891  * Allocate a new DTD and fill the fields.
892  */
893  cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
894  if (cur == NULL) {
895  xmlTreeErrMemory("building DTD");
896  return(NULL);
897  }
898  memset(cur, 0 , sizeof(xmlDtd));
899  cur->type = XML_DTD_NODE;
900 
901  if (name != NULL)
902  cur->name = xmlStrdup(name);
903  if (ExternalID != NULL)
904  cur->ExternalID = xmlStrdup(ExternalID);
905  if (SystemID != NULL)
906  cur->SystemID = xmlStrdup(SystemID);
907  if (doc != NULL)
908  doc->extSubset = cur;
909  cur->doc = doc;
910 
913  return(cur);
914 }
915 
924 xmlDtdPtr
925 xmlGetIntSubset(const xmlDoc *doc) {
926  xmlNodePtr cur;
927 
928  if (doc == NULL)
929  return(NULL);
930  cur = doc->children;
931  while (cur != NULL) {
932  if (cur->type == XML_DTD_NODE)
933  return((xmlDtdPtr) cur);
934  cur = cur->next;
935  }
936  return((xmlDtdPtr) doc->intSubset);
937 }
938 
949 xmlDtdPtr
951  const xmlChar *ExternalID, const xmlChar *SystemID) {
952  xmlDtdPtr cur;
953 
954  if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
955 #ifdef DEBUG_TREE
957 
958  "xmlCreateIntSubset(): document %s already have an internal subset\n",
959  doc->name);
960 #endif
961  return(NULL);
962  }
963 
964  /*
965  * Allocate a new DTD and fill the fields.
966  */
967  cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
968  if (cur == NULL) {
969  xmlTreeErrMemory("building internal subset");
970  return(NULL);
971  }
972  memset(cur, 0, sizeof(xmlDtd));
973  cur->type = XML_DTD_NODE;
974 
975  if (name != NULL) {
976  cur->name = xmlStrdup(name);
977  if (cur->name == NULL) {
978  xmlTreeErrMemory("building internal subset");
979  xmlFree(cur);
980  return(NULL);
981  }
982  }
983  if (ExternalID != NULL) {
984  cur->ExternalID = xmlStrdup(ExternalID);
985  if (cur->ExternalID == NULL) {
986  xmlTreeErrMemory("building internal subset");
987  if (cur->name != NULL)
988  xmlFree((char *)cur->name);
989  xmlFree(cur);
990  return(NULL);
991  }
992  }
993  if (SystemID != NULL) {
994  cur->SystemID = xmlStrdup(SystemID);
995  if (cur->SystemID == NULL) {
996  xmlTreeErrMemory("building internal subset");
997  if (cur->name != NULL)
998  xmlFree((char *)cur->name);
999  if (cur->ExternalID != NULL)
1000  xmlFree((char *)cur->ExternalID);
1001  xmlFree(cur);
1002  return(NULL);
1003  }
1004  }
1005  if (doc != NULL) {
1006  doc->intSubset = cur;
1007  cur->parent = doc;
1008  cur->doc = doc;
1009  if (doc->children == NULL) {
1010  doc->children = (xmlNodePtr) cur;
1011  doc->last = (xmlNodePtr) cur;
1012  } else {
1013  if (doc->type == XML_HTML_DOCUMENT_NODE) {
1014  xmlNodePtr prev;
1015 
1016  prev = doc->children;
1017  prev->prev = (xmlNodePtr) cur;
1018  cur->next = prev;
1019  doc->children = (xmlNodePtr) cur;
1020  } else {
1021  xmlNodePtr next;
1022 
1023  next = doc->children;
1024  while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1025  next = next->next;
1026  if (next == NULL) {
1027  cur->prev = doc->last;
1028  cur->prev->next = (xmlNodePtr) cur;
1029  cur->next = NULL;
1030  doc->last = (xmlNodePtr) cur;
1031  } else {
1032  cur->next = next;
1033  cur->prev = next->prev;
1034  if (cur->prev == NULL)
1035  doc->children = (xmlNodePtr) cur;
1036  else
1037  cur->prev->next = (xmlNodePtr) cur;
1038  next->prev = (xmlNodePtr) cur;
1039  }
1040  }
1041  }
1042  }
1043 
1046  return(cur);
1047 }
1048 
1056 #define DICT_FREE(str) \
1057  if ((str) && ((!dict) || \
1058  (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1059  xmlFree((char *)(str));
1060 
1061 
1069 #define DICT_COPY(str, cpy) \
1070  if (str) { \
1071  if (dict) { \
1072  if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1073  cpy = (xmlChar *) (str); \
1074  else \
1075  cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1076  } else \
1077  cpy = xmlStrdup((const xmlChar *)(str)); }
1078 
1086 #define DICT_CONST_COPY(str, cpy) \
1087  if (str) { \
1088  if (dict) { \
1089  if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1090  cpy = (const xmlChar *) (str); \
1091  else \
1092  cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1093  } else \
1094  cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1095 
1096 
1103 void
1104 xmlFreeDtd(xmlDtdPtr cur) {
1105  xmlDictPtr dict = NULL;
1106 
1107  if (cur == NULL) {
1108  return;
1109  }
1110  if (cur->doc != NULL) dict = cur->doc->dict;
1111 
1114 
1115  if (cur->children != NULL) {
1116  xmlNodePtr next, c = cur->children;
1117 
1118  /*
1119  * Cleanup all nodes which are not part of the specific lists
1120  * of notations, elements, attributes and entities.
1121  */
1122  while (c != NULL) {
1123  next = c->next;
1124  if ((c->type != XML_NOTATION_NODE) &&
1125  (c->type != XML_ELEMENT_DECL) &&
1126  (c->type != XML_ATTRIBUTE_DECL) &&
1127  (c->type != XML_ENTITY_DECL)) {
1128  xmlUnlinkNode(c);
1129  xmlFreeNode(c);
1130  }
1131  c = next;
1132  }
1133  }
1134  DICT_FREE(cur->name)
1135  DICT_FREE(cur->SystemID)
1136  DICT_FREE(cur->ExternalID)
1137  /* TODO !!! */
1138  if (cur->notations != NULL)
1139  xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1140 
1141  if (cur->elements != NULL)
1142  xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1143  if (cur->attributes != NULL)
1144  xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1145  if (cur->entities != NULL)
1147  if (cur->pentities != NULL)
1148  xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1149 
1150  xmlFree(cur);
1151 }
1152 
1161 xmlDocPtr
1163  xmlDocPtr cur;
1164 
1165  if (version == NULL)
1166  version = (const xmlChar *) "1.0";
1167 
1168  /*
1169  * Allocate a new document and fill the fields.
1170  */
1171  cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1172  if (cur == NULL) {
1173  xmlTreeErrMemory("building doc");
1174  return(NULL);
1175  }
1176  memset(cur, 0, sizeof(xmlDoc));
1177  cur->type = XML_DOCUMENT_NODE;
1178 
1179  cur->version = xmlStrdup(version);
1180  if (cur->version == NULL) {
1181  xmlTreeErrMemory("building doc");
1182  xmlFree(cur);
1183  return(NULL);
1184  }
1185  cur->standalone = -1;
1186  cur->compression = -1; /* not initialized */
1187  cur->doc = cur;
1188  cur->parseFlags = 0;
1190  /*
1191  * The in memory encoding is always UTF8
1192  * This field will never change and would
1193  * be obsolete if not for binary compatibility.
1194  */
1196 
1199  return(cur);
1200 }
1201 
1208 void
1209 xmlFreeDoc(xmlDocPtr cur) {
1210  xmlDtdPtr extSubset, intSubset;
1211  xmlDictPtr dict = NULL;
1212 
1213  if (cur == NULL) {
1214 #ifdef DEBUG_TREE
1216  "xmlFreeDoc : document == NULL\n");
1217 #endif
1218  return;
1219  }
1220 #ifdef LIBXML_DEBUG_RUNTIME
1221 #ifdef LIBXML_DEBUG_ENABLED
1222  xmlDebugCheckDocument(stderr, cur);
1223 #endif
1224 #endif
1225 
1226  if (cur != NULL) dict = cur->dict;
1227 
1230 
1231  /*
1232  * Do this before freeing the children list to avoid ID lookups
1233  */
1234  if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1235  cur->ids = NULL;
1236  if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1237  cur->refs = NULL;
1238  extSubset = cur->extSubset;
1239  intSubset = cur->intSubset;
1240  if (intSubset == extSubset)
1241  extSubset = NULL;
1242  if (extSubset != NULL) {
1244  cur->extSubset = NULL;
1245  xmlFreeDtd(extSubset);
1246  }
1247  if (intSubset != NULL) {
1249  cur->intSubset = NULL;
1250  xmlFreeDtd(intSubset);
1251  }
1252 
1253  if (cur->children != NULL) xmlFreeNodeList(cur->children);
1254  if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1255 
1256  DICT_FREE(cur->version)
1257  DICT_FREE(cur->name)
1258  DICT_FREE(cur->encoding)
1259  DICT_FREE(cur->URL)
1260  xmlFree(cur);
1261  if (dict) xmlDictFree(dict);
1262 }
1263 
1274 xmlNodePtr
1276  xmlNodePtr ret = NULL, last = NULL;
1277  xmlNodePtr node;
1278  xmlChar *val;
1279  const xmlChar *cur = value, *end = cur + len;
1280  const xmlChar *q;
1281  xmlEntityPtr ent;
1282  xmlBufPtr buf;
1283 
1284  if (value == NULL) return(NULL);
1285 
1286  buf = xmlBufCreateSize(0);
1287  if (buf == NULL) return(NULL);
1289 
1290  q = cur;
1291  while ((cur < end) && (*cur != 0)) {
1292  if (cur[0] == '&') {
1293  int charval = 0;
1294  xmlChar tmp;
1295 
1296  /*
1297  * Save the current text.
1298  */
1299  if (cur != q) {
1300  if (xmlBufAdd(buf, q, cur - q))
1301  goto out;
1302  }
1303  q = cur;
1304  if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1305  cur += 3;
1306  if (cur < end)
1307  tmp = *cur;
1308  else
1309  tmp = 0;
1310  while (tmp != ';') { /* Non input consuming loop */
1311  if ((tmp >= '0') && (tmp <= '9'))
1312  charval = charval * 16 + (tmp - '0');
1313  else if ((tmp >= 'a') && (tmp <= 'f'))
1314  charval = charval * 16 + (tmp - 'a') + 10;
1315  else if ((tmp >= 'A') && (tmp <= 'F'))
1316  charval = charval * 16 + (tmp - 'A') + 10;
1317  else {
1318  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1319  NULL);
1320  charval = 0;
1321  break;
1322  }
1323  cur++;
1324  if (cur < end)
1325  tmp = *cur;
1326  else
1327  tmp = 0;
1328  }
1329  if (tmp == ';')
1330  cur++;
1331  q = cur;
1332  } else if ((cur + 1 < end) && (cur[1] == '#')) {
1333  cur += 2;
1334  if (cur < end)
1335  tmp = *cur;
1336  else
1337  tmp = 0;
1338  while (tmp != ';') { /* Non input consuming loops */
1339  if ((tmp >= '0') && (tmp <= '9'))
1340  charval = charval * 10 + (tmp - '0');
1341  else {
1342  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1343  NULL);
1344  charval = 0;
1345  break;
1346  }
1347  cur++;
1348  if (cur < end)
1349  tmp = *cur;
1350  else
1351  tmp = 0;
1352  }
1353  if (tmp == ';')
1354  cur++;
1355  q = cur;
1356  } else {
1357  /*
1358  * Read the entity string
1359  */
1360  cur++;
1361  q = cur;
1362  while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1363  if ((cur >= end) || (*cur == 0)) {
1364  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1365  (const char *) q);
1366  goto out;
1367  }
1368  if (cur != q) {
1369  /*
1370  * Predefined entities don't generate nodes
1371  */
1372  val = xmlStrndup(q, cur - q);
1373  ent = xmlGetDocEntity(doc, val);
1374  if ((ent != NULL) &&
1376 
1377  if (xmlBufCat(buf, ent->content))
1378  goto out;
1379 
1380  } else {
1381  /*
1382  * Flush buffer so far
1383  */
1384  if (!xmlBufIsEmpty(buf)) {
1385  node = xmlNewDocText(doc, NULL);
1386  if (node == NULL) {
1387  if (val != NULL) xmlFree(val);
1388  goto out;
1389  }
1390  node->content = xmlBufDetach(buf);
1391 
1392  if (last == NULL) {
1393  last = ret = node;
1394  } else {
1396  }
1397  }
1398 
1399  /*
1400  * Create a new REFERENCE_REF node
1401  */
1402  node = xmlNewReference(doc, val);
1403  if (node == NULL) {
1404  if (val != NULL) xmlFree(val);
1405  goto out;
1406  }
1407  else if ((ent != NULL) && (ent->children == NULL)) {
1408  xmlNodePtr temp;
1409 
1410  /* Set to non-NULL value to avoid recursion. */
1411  ent->children = (xmlNodePtr) -1;
1412  ent->children = xmlStringGetNodeList(doc,
1413  (const xmlChar*)node->content);
1414  ent->owner = 1;
1415  temp = ent->children;
1416  while (temp) {
1417  temp->parent = (xmlNodePtr)ent;
1418  ent->last = temp;
1419  temp = temp->next;
1420  }
1421  }
1422  if (last == NULL) {
1423  last = ret = node;
1424  } else {
1426  }
1427  }
1428  xmlFree(val);
1429  }
1430  cur++;
1431  q = cur;
1432  }
1433  if (charval != 0) {
1434  xmlChar buffer[10];
1435  int l;
1436 
1437  l = xmlCopyCharMultiByte(buffer, charval);
1438  buffer[l] = 0;
1439 
1440  if (xmlBufCat(buf, buffer))
1441  goto out;
1442  charval = 0;
1443  }
1444  } else
1445  cur++;
1446  }
1447 
1448  if (cur != q) {
1449  /*
1450  * Handle the last piece of text.
1451  */
1452  if (xmlBufAdd(buf, q, cur - q))
1453  goto out;
1454  }
1455 
1456  if (!xmlBufIsEmpty(buf)) {
1457  node = xmlNewDocText(doc, NULL);
1458  if (node == NULL) goto out;
1459  node->content = xmlBufDetach(buf);
1460 
1461  if (last == NULL) {
1462  ret = node;
1463  } else {
1465  }
1466  } else if (ret == NULL) {
1467  ret = xmlNewDocText(doc, BAD_CAST "");
1468  }
1469 
1470 out:
1471  xmlBufFree(buf);
1472  return(ret);
1473 }
1474 
1484 xmlNodePtr
1485 xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1486  xmlNodePtr ret = NULL, last = NULL;
1487  xmlNodePtr node;
1488  xmlChar *val;
1489  const xmlChar *cur = value;
1490  const xmlChar *q;
1491  xmlEntityPtr ent;
1492  xmlBufPtr buf;
1493 
1494  if (value == NULL) return(NULL);
1495 
1496  buf = xmlBufCreateSize(0);
1497  if (buf == NULL) return(NULL);
1499 
1500  q = cur;
1501  while (*cur != 0) {
1502  if (cur[0] == '&') {
1503  int charval = 0;
1504  xmlChar tmp;
1505 
1506  /*
1507  * Save the current text.
1508  */
1509  if (cur != q) {
1510  if (xmlBufAdd(buf, q, cur - q))
1511  goto out;
1512  }
1513  q = cur;
1514  if ((cur[1] == '#') && (cur[2] == 'x')) {
1515  cur += 3;
1516  tmp = *cur;
1517  while (tmp != ';') { /* Non input consuming loop */
1518  if ((tmp >= '0') && (tmp <= '9'))
1519  charval = charval * 16 + (tmp - '0');
1520  else if ((tmp >= 'a') && (tmp <= 'f'))
1521  charval = charval * 16 + (tmp - 'a') + 10;
1522  else if ((tmp >= 'A') && (tmp <= 'F'))
1523  charval = charval * 16 + (tmp - 'A') + 10;
1524  else {
1525  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1526  NULL);
1527  charval = 0;
1528  break;
1529  }
1530  cur++;
1531  tmp = *cur;
1532  }
1533  if (tmp == ';')
1534  cur++;
1535  q = cur;
1536  } else if (cur[1] == '#') {
1537  cur += 2;
1538  tmp = *cur;
1539  while (tmp != ';') { /* Non input consuming loops */
1540  if ((tmp >= '0') && (tmp <= '9'))
1541  charval = charval * 10 + (tmp - '0');
1542  else {
1543  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1544  NULL);
1545  charval = 0;
1546  break;
1547  }
1548  cur++;
1549  tmp = *cur;
1550  }
1551  if (tmp == ';')
1552  cur++;
1553  q = cur;
1554  } else {
1555  /*
1556  * Read the entity string
1557  */
1558  cur++;
1559  q = cur;
1560  while ((*cur != 0) && (*cur != ';')) cur++;
1561  if (*cur == 0) {
1562  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1563  (xmlNodePtr) doc, (const char *) q);
1564  goto out;
1565  }
1566  if (cur != q) {
1567  /*
1568  * Predefined entities don't generate nodes
1569  */
1570  val = xmlStrndup(q, cur - q);
1571  ent = xmlGetDocEntity(doc, val);
1572  if ((ent != NULL) &&
1574 
1575  if (xmlBufCat(buf, ent->content))
1576  goto out;
1577 
1578  } else {
1579  /*
1580  * Flush buffer so far
1581  */
1582  if (!xmlBufIsEmpty(buf)) {
1583  node = xmlNewDocText(doc, NULL);
1584  node->content = xmlBufDetach(buf);
1585 
1586  if (last == NULL) {
1587  last = ret = node;
1588  } else {
1590  }
1591  }
1592 
1593  /*
1594  * Create a new REFERENCE_REF node
1595  */
1596  node = xmlNewReference(doc, val);
1597  if (node == NULL) {
1598  if (val != NULL) xmlFree(val);
1599  goto out;
1600  }
1601  else if ((ent != NULL) && (ent->children == NULL)) {
1602  xmlNodePtr temp;
1603 
1604  /* Set to non-NULL value to avoid recursion. */
1605  ent->children = (xmlNodePtr) -1;
1606  ent->children = xmlStringGetNodeList(doc,
1607  (const xmlChar*)node->content);
1608  ent->owner = 1;
1609  temp = ent->children;
1610  while (temp) {
1611  temp->parent = (xmlNodePtr)ent;
1612  ent->last = temp;
1613  temp = temp->next;
1614  }
1615  }
1616  if (last == NULL) {
1617  last = ret = node;
1618  } else {
1620  }
1621  }
1622  xmlFree(val);
1623  }
1624  cur++;
1625  q = cur;
1626  }
1627  if (charval != 0) {
1628  xmlChar buffer[10];
1629  int len;
1630 
1631  len = xmlCopyCharMultiByte(buffer, charval);
1632  buffer[len] = 0;
1633 
1634  if (xmlBufCat(buf, buffer))
1635  goto out;
1636  charval = 0;
1637  }
1638  } else
1639  cur++;
1640  }
1641  if ((cur != q) || (ret == NULL)) {
1642  /*
1643  * Handle the last piece of text.
1644  */
1645  xmlBufAdd(buf, q, cur - q);
1646  }
1647 
1648  if (!xmlBufIsEmpty(buf)) {
1649  node = xmlNewDocText(doc, NULL);
1650  node->content = xmlBufDetach(buf);
1651 
1652  if (last == NULL) {
1653  ret = node;
1654  } else {
1656  }
1657  }
1658 
1659 out:
1660  xmlBufFree(buf);
1661  return(ret);
1662 }
1663 
1675 xmlChar *
1676 xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1677 {
1678  const xmlNode *node = list;
1679  xmlChar *ret = NULL;
1680  xmlEntityPtr ent;
1681  int attr;
1682 
1683  if (list == NULL)
1684  return (NULL);
1685  if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1686  attr = 1;
1687  else
1688  attr = 0;
1689 
1690  while (node != NULL) {
1691  if ((node->type == XML_TEXT_NODE) ||
1692  (node->type == XML_CDATA_SECTION_NODE)) {
1693  if (inLine) {
1694  ret = xmlStrcat(ret, node->content);
1695  } else {
1696  xmlChar *buffer;
1697 
1698  if (attr)
1699  buffer = xmlEncodeAttributeEntities(doc, node->content);
1700  else
1701  buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1702  if (buffer != NULL) {
1703  ret = xmlStrcat(ret, buffer);
1704  xmlFree(buffer);
1705  }
1706  }
1707  } else if (node->type == XML_ENTITY_REF_NODE) {
1708  if (inLine) {
1709  ent = xmlGetDocEntity(doc, node->name);
1710  if (ent != NULL) {
1711  xmlChar *buffer;
1712 
1713  /* an entity content can be any "well balanced chunk",
1714  * i.e. the result of the content [43] production:
1715  * http://www.w3.org/TR/REC-xml#NT-content.
1716  * So it can contain text, CDATA section or nested
1717  * entity reference nodes (among others).
1718  * -> we recursive call xmlNodeListGetString()
1719  * which handles these types */
1720  buffer = xmlNodeListGetString(doc, ent->children, 1);
1721  if (buffer != NULL) {
1722  ret = xmlStrcat(ret, buffer);
1723  xmlFree(buffer);
1724  }
1725  } else {
1726  ret = xmlStrcat(ret, node->content);
1727  }
1728  } else {
1729  xmlChar buf[2];
1730 
1731  buf[0] = '&';
1732  buf[1] = 0;
1733  ret = xmlStrncat(ret, buf, 1);
1734  ret = xmlStrcat(ret, node->name);
1735  buf[0] = ';';
1736  buf[1] = 0;
1737  ret = xmlStrncat(ret, buf, 1);
1738  }
1739  }
1740 #if 0
1741  else {
1743  "xmlGetNodeListString : invalid node type %d\n",
1744  node->type);
1745  }
1746 #endif
1747  node = node->next;
1748  }
1749  return (ret);
1750 }
1751 
1752 #ifdef LIBXML_TREE_ENABLED
1753 
1765 xmlChar *
1766 xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1767 {
1768  const xmlNode *node = list;
1769  xmlChar *ret = NULL;
1770  xmlEntityPtr ent;
1771 
1772  if (list == NULL)
1773  return (NULL);
1774 
1775  while (node != NULL) {
1776  if ((node->type == XML_TEXT_NODE) ||
1777  (node->type == XML_CDATA_SECTION_NODE)) {
1778  if (inLine) {
1779  ret = xmlStrcat(ret, node->content);
1780  } else {
1781  xmlChar *buffer;
1782 
1783  buffer = xmlEncodeSpecialChars(doc, node->content);
1784  if (buffer != NULL) {
1785  ret = xmlStrcat(ret, buffer);
1786  xmlFree(buffer);
1787  }
1788  }
1789  } else if (node->type == XML_ENTITY_REF_NODE) {
1790  if (inLine) {
1791  ent = xmlGetDocEntity(doc, node->name);
1792  if (ent != NULL) {
1793  xmlChar *buffer;
1794 
1795  /* an entity content can be any "well balanced chunk",
1796  * i.e. the result of the content [43] production:
1797  * http://www.w3.org/TR/REC-xml#NT-content.
1798  * So it can contain text, CDATA section or nested
1799  * entity reference nodes (among others).
1800  * -> we recursive call xmlNodeListGetRawString()
1801  * which handles these types */
1802  buffer =
1803  xmlNodeListGetRawString(doc, ent->children, 1);
1804  if (buffer != NULL) {
1805  ret = xmlStrcat(ret, buffer);
1806  xmlFree(buffer);
1807  }
1808  } else {
1809  ret = xmlStrcat(ret, node->content);
1810  }
1811  } else {
1812  xmlChar buf[2];
1813 
1814  buf[0] = '&';
1815  buf[1] = 0;
1816  ret = xmlStrncat(ret, buf, 1);
1817  ret = xmlStrcat(ret, node->name);
1818  buf[0] = ';';
1819  buf[1] = 0;
1820  ret = xmlStrncat(ret, buf, 1);
1821  }
1822  }
1823 #if 0
1824  else {
1826  "xmlGetNodeListString : invalid node type %d\n",
1827  node->type);
1828  }
1829 #endif
1830  node = node->next;
1831  }
1832  return (ret);
1833 }
1834 #endif /* LIBXML_TREE_ENABLED */
1835 
1836 static xmlAttrPtr
1837 xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1838  const xmlChar * name, const xmlChar * value,
1839  int eatname)
1840 {
1841  xmlAttrPtr cur;
1842  xmlDocPtr doc = NULL;
1843 
1844  if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1845  if ((eatname == 1) &&
1846  ((node->doc == NULL) ||
1847  (!(xmlDictOwns(node->doc->dict, name)))))
1848  xmlFree((xmlChar *) name);
1849  return (NULL);
1850  }
1851 
1852  /*
1853  * Allocate a new property and fill the fields.
1854  */
1855  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1856  if (cur == NULL) {
1857  if ((eatname == 1) &&
1858  ((node == NULL) || (node->doc == NULL) ||
1859  (!(xmlDictOwns(node->doc->dict, name)))))
1860  xmlFree((xmlChar *) name);
1861  xmlTreeErrMemory("building attribute");
1862  return (NULL);
1863  }
1864  memset(cur, 0, sizeof(xmlAttr));
1865  cur->type = XML_ATTRIBUTE_NODE;
1866 
1867  cur->parent = node;
1868  if (node != NULL) {
1869  doc = node->doc;
1870  cur->doc = doc;
1871  }
1872  cur->ns = ns;
1873 
1874  if (eatname == 0) {
1875  if ((doc != NULL) && (doc->dict != NULL))
1876  cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1877  else
1878  cur->name = xmlStrdup(name);
1879  } else
1880  cur->name = name;
1881 
1882  if (value != NULL) {
1883  xmlNodePtr tmp;
1884 
1885  if(!xmlCheckUTF8(value)) {
1886  xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
1887  NULL);
1888  if (doc != NULL)
1889  doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1890  }
1891  cur->children = xmlNewDocText(doc, value);
1892  cur->last = NULL;
1893  tmp = cur->children;
1894  while (tmp != NULL) {
1895  tmp->parent = (xmlNodePtr) cur;
1896  if (tmp->next == NULL)
1897  cur->last = tmp;
1898  tmp = tmp->next;
1899  }
1900  }
1901 
1902  /*
1903  * Add it at the end to preserve parsing order ...
1904  */
1905  if (node != NULL) {
1906  if (node->properties == NULL) {
1907  node->properties = cur;
1908  } else {
1909  xmlAttrPtr prev = node->properties;
1910 
1911  while (prev->next != NULL)
1912  prev = prev->next;
1913  prev->next = cur;
1914  cur->prev = prev;
1915  }
1916  }
1917 
1918  if ((value != NULL) && (node != NULL) &&
1919  (xmlIsID(node->doc, node, cur) == 1))
1920  xmlAddID(NULL, node->doc, value, cur);
1921 
1924  return (cur);
1925 }
1926 
1927 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1928  defined(LIBXML_SCHEMAS_ENABLED)
1929 
1938 xmlAttrPtr
1939 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1940 
1941  if (name == NULL) {
1942 #ifdef DEBUG_TREE
1944  "xmlNewProp : name == NULL\n");
1945 #endif
1946  return(NULL);
1947  }
1948 
1949  return xmlNewPropInternal(node, NULL, name, value, 0);
1950 }
1951 #endif /* LIBXML_TREE_ENABLED */
1952 
1963 xmlAttrPtr
1965  const xmlChar *value) {
1966 
1967  if (name == NULL) {
1968 #ifdef DEBUG_TREE
1970  "xmlNewNsProp : name == NULL\n");
1971 #endif
1972  return(NULL);
1973  }
1974 
1975  return xmlNewPropInternal(node, ns, name, value, 0);
1976 }
1977 
1988 xmlAttrPtr
1990  const xmlChar *value) {
1991 
1992  if (name == NULL) {
1993 #ifdef DEBUG_TREE
1995  "xmlNewNsPropEatName : name == NULL\n");
1996 #endif
1997  return(NULL);
1998  }
1999 
2000  return xmlNewPropInternal(node, ns, name, value, 1);
2001 }
2002 
2012 xmlAttrPtr
2013 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
2014  xmlAttrPtr cur;
2015 
2016  if (name == NULL) {
2017 #ifdef DEBUG_TREE
2019  "xmlNewDocProp : name == NULL\n");
2020 #endif
2021  return(NULL);
2022  }
2023 
2024  /*
2025  * Allocate a new property and fill the fields.
2026  */
2027  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2028  if (cur == NULL) {
2029  xmlTreeErrMemory("building attribute");
2030  return(NULL);
2031  }
2032  memset(cur, 0, sizeof(xmlAttr));
2033  cur->type = XML_ATTRIBUTE_NODE;
2034 
2035  if ((doc != NULL) && (doc->dict != NULL))
2036  cur->name = xmlDictLookup(doc->dict, name, -1);
2037  else
2038  cur->name = xmlStrdup(name);
2039  cur->doc = doc;
2040  if (value != NULL) {
2041  xmlNodePtr tmp;
2042 
2043  cur->children = xmlStringGetNodeList(doc, value);
2044  cur->last = NULL;
2045 
2046  tmp = cur->children;
2047  while (tmp != NULL) {
2048  tmp->parent = (xmlNodePtr) cur;
2049  if (tmp->next == NULL)
2050  cur->last = tmp;
2051  tmp = tmp->next;
2052  }
2053  }
2054 
2057  return(cur);
2058 }
2059 
2066 void
2068  xmlAttrPtr next;
2069  if (cur == NULL) return;
2070  while (cur != NULL) {
2071  next = cur->next;
2072  xmlFreeProp(cur);
2073  cur = next;
2074  }
2075 }
2076 
2083 void
2084 xmlFreeProp(xmlAttrPtr cur) {
2085  xmlDictPtr dict = NULL;
2086  if (cur == NULL) return;
2087 
2088  if (cur->doc != NULL) dict = cur->doc->dict;
2089 
2092 
2093  /* Check for ID removal -> leading to invalid references ! */
2094  if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2095  xmlRemoveID(cur->doc, cur);
2096  }
2097  if (cur->children != NULL) xmlFreeNodeList(cur->children);
2098  DICT_FREE(cur->name)
2099  xmlFree(cur);
2100 }
2101 
2111 int
2113  xmlAttrPtr tmp;
2114  if (cur == NULL) {
2115 #ifdef DEBUG_TREE
2117  "xmlRemoveProp : cur == NULL\n");
2118 #endif
2119  return(-1);
2120  }
2121  if (cur->parent == NULL) {
2122 #ifdef DEBUG_TREE
2124  "xmlRemoveProp : cur->parent == NULL\n");
2125 #endif
2126  return(-1);
2127  }
2128  tmp = cur->parent->properties;
2129  if (tmp == cur) {
2130  cur->parent->properties = cur->next;
2131  if (cur->next != NULL)
2132  cur->next->prev = NULL;
2133  xmlFreeProp(cur);
2134  return(0);
2135  }
2136  while (tmp != NULL) {
2137  if (tmp->next == cur) {
2138  tmp->next = cur->next;
2139  if (tmp->next != NULL)
2140  tmp->next->prev = tmp;
2141  xmlFreeProp(cur);
2142  return(0);
2143  }
2144  tmp = tmp->next;
2145  }
2146 #ifdef DEBUG_TREE
2148  "xmlRemoveProp : attribute not owned by its node\n");
2149 #endif
2150  return(-1);
2151 }
2152 
2162 xmlNodePtr
2163 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2164  xmlNodePtr cur;
2165 
2166  if (name == NULL) {
2167 #ifdef DEBUG_TREE
2169  "xmlNewPI : name == NULL\n");
2170 #endif
2171  return(NULL);
2172  }
2173 
2174  /*
2175  * Allocate a new node and fill the fields.
2176  */
2177  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2178  if (cur == NULL) {
2179  xmlTreeErrMemory("building PI");
2180  return(NULL);
2181  }
2182  memset(cur, 0, sizeof(xmlNode));
2183  cur->type = XML_PI_NODE;
2184 
2185  if ((doc != NULL) && (doc->dict != NULL))
2186  cur->name = xmlDictLookup(doc->dict, name, -1);
2187  else
2188  cur->name = xmlStrdup(name);
2189  if (content != NULL) {
2190  cur->content = xmlStrdup(content);
2191  }
2192  cur->doc = doc;
2193 
2196  return(cur);
2197 }
2198 
2209 xmlNodePtr
2210 xmlNewPI(const xmlChar *name, const xmlChar *content) {
2211  return(xmlNewDocPI(NULL, name, content));
2212 }
2213 
2224 xmlNodePtr
2225 xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2226  xmlNodePtr cur;
2227 
2228  if (name == NULL) {
2229 #ifdef DEBUG_TREE
2231  "xmlNewNode : name == NULL\n");
2232 #endif
2233  return(NULL);
2234  }
2235 
2236  /*
2237  * Allocate a new node and fill the fields.
2238  */
2239  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2240  if (cur == NULL) {
2241  xmlTreeErrMemory("building node");
2242  return(NULL);
2243  }
2244  memset(cur, 0, sizeof(xmlNode));
2245  cur->type = XML_ELEMENT_NODE;
2246 
2247  cur->name = xmlStrdup(name);
2248  cur->ns = ns;
2249 
2252  return(cur);
2253 }
2254 
2266 xmlNodePtr
2268  xmlNodePtr cur;
2269 
2270  if (name == NULL) {
2271 #ifdef DEBUG_TREE
2273  "xmlNewNode : name == NULL\n");
2274 #endif
2275  return(NULL);
2276  }
2277 
2278  /*
2279  * Allocate a new node and fill the fields.
2280  */
2281  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2282  if (cur == NULL) {
2283  xmlTreeErrMemory("building node");
2284  /* we can't check here that name comes from the doc dictionary */
2285  return(NULL);
2286  }
2287  memset(cur, 0, sizeof(xmlNode));
2288  cur->type = XML_ELEMENT_NODE;
2289 
2290  cur->name = name;
2291  cur->ns = ns;
2292 
2295  return(cur);
2296 }
2297 
2314 xmlNodePtr
2316  const xmlChar *name, const xmlChar *content) {
2317  xmlNodePtr cur;
2318 
2319  if ((doc != NULL) && (doc->dict != NULL))
2320  cur = xmlNewNodeEatName(ns, (xmlChar *)
2321  xmlDictLookup(doc->dict, name, -1));
2322  else
2323  cur = xmlNewNode(ns, name);
2324  if (cur != NULL) {
2325  cur->doc = doc;
2326  if (content != NULL) {
2327  cur->children = xmlStringGetNodeList(doc, content);
2329  }
2330  }
2331 
2332  return(cur);
2333 }
2334 
2351 xmlNodePtr
2353  xmlChar *name, const xmlChar *content) {
2354  xmlNodePtr cur;
2355 
2356  cur = xmlNewNodeEatName(ns, name);
2357  if (cur != NULL) {
2358  cur->doc = doc;
2359  if (content != NULL) {
2360  cur->children = xmlStringGetNodeList(doc, content);
2362  }
2363  } else {
2364  /* if name don't come from the doc dictionary free it here */
2365  if ((name != NULL) && (doc != NULL) &&
2366  (!(xmlDictOwns(doc->dict, name))))
2367  xmlFree(name);
2368  }
2369  return(cur);
2370 }
2371 
2372 #ifdef LIBXML_TREE_ENABLED
2373 
2385 xmlNodePtr
2386 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2387  const xmlChar *name, const xmlChar *content) {
2388  xmlNodePtr cur;
2389 
2390  cur = xmlNewDocNode(doc, ns, name, NULL);
2391  if (cur != NULL) {
2392  cur->doc = doc;
2393  if (content != NULL) {
2394  cur->children = xmlNewDocText(doc, content);
2396  }
2397  }
2398  return(cur);
2399 }
2400 
2408 xmlNodePtr
2409 xmlNewDocFragment(xmlDocPtr doc) {
2410  xmlNodePtr cur;
2411 
2412  /*
2413  * Allocate a new DocumentFragment node and fill the fields.
2414  */
2415  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2416  if (cur == NULL) {
2417  xmlTreeErrMemory("building fragment");
2418  return(NULL);
2419  }
2420  memset(cur, 0, sizeof(xmlNode));
2422 
2423  cur->doc = doc;
2424 
2427  return(cur);
2428 }
2429 #endif /* LIBXML_TREE_ENABLED */
2430 
2438 xmlNodePtr
2439 xmlNewText(const xmlChar *content) {
2440  xmlNodePtr cur;
2441 
2442  /*
2443  * Allocate a new node and fill the fields.
2444  */
2445  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2446  if (cur == NULL) {
2447  xmlTreeErrMemory("building text");
2448  return(NULL);
2449  }
2450  memset(cur, 0, sizeof(xmlNode));
2451  cur->type = XML_TEXT_NODE;
2452 
2453  cur->name = xmlStringText;
2454  if (content != NULL) {
2455  cur->content = xmlStrdup(content);
2456  }
2457 
2460  return(cur);
2461 }
2462 
2463 #ifdef LIBXML_TREE_ENABLED
2464 
2483 xmlNodePtr
2484 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2485  const xmlChar *name, const xmlChar *content) {
2486  xmlNodePtr cur, prev;
2487 
2488  if (parent == NULL) {
2489 #ifdef DEBUG_TREE
2491  "xmlNewTextChild : parent == NULL\n");
2492 #endif
2493  return(NULL);
2494  }
2495 
2496  if (name == NULL) {
2497 #ifdef DEBUG_TREE
2499  "xmlNewTextChild : name == NULL\n");
2500 #endif
2501  return(NULL);
2502  }
2503 
2504  /*
2505  * Allocate a new node
2506  */
2507  if (parent->type == XML_ELEMENT_NODE) {
2508  if (ns == NULL)
2509  cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2510  else
2511  cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2512  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2513  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2514  if (ns == NULL)
2515  cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2516  else
2517  cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2518  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2519  cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2520  } else {
2521  return(NULL);
2522  }
2523  if (cur == NULL) return(NULL);
2524 
2525  /*
2526  * add the new element at the end of the children list.
2527  */
2528  cur->type = XML_ELEMENT_NODE;
2529  cur->parent = parent;
2530  cur->doc = parent->doc;
2531  if (parent->children == NULL) {
2532  parent->children = cur;
2533  parent->last = cur;
2534  } else {
2535  prev = parent->last;
2536  prev->next = cur;
2537  cur->prev = prev;
2538  parent->last = cur;
2539  }
2540 
2541  return(cur);
2542 }
2543 #endif /* LIBXML_TREE_ENABLED */
2544 
2553 xmlNodePtr
2554 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2555  xmlNodePtr cur;
2556 
2557  if (name == NULL)
2558  return(NULL);
2559 
2560  /*
2561  * Allocate a new node and fill the fields.
2562  */
2563  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2564  if (cur == NULL) {
2565  xmlTreeErrMemory("building character reference");
2566  return(NULL);
2567  }
2568  memset(cur, 0, sizeof(xmlNode));
2569  cur->type = XML_ENTITY_REF_NODE;
2570 
2571  cur->doc = doc;
2572  if (name[0] == '&') {
2573  int len;
2574  name++;
2575  len = xmlStrlen(name);
2576  if (name[len - 1] == ';')
2577  cur->name = xmlStrndup(name, len - 1);
2578  else
2579  cur->name = xmlStrndup(name, len);
2580  } else
2581  cur->name = xmlStrdup(name);
2582 
2585  return(cur);
2586 }
2587 
2596 xmlNodePtr
2597 xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2598  xmlNodePtr cur;
2599  xmlEntityPtr ent;
2600 
2601  if (name == NULL)
2602  return(NULL);
2603 
2604  /*
2605  * Allocate a new node and fill the fields.
2606  */
2607  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2608  if (cur == NULL) {
2609  xmlTreeErrMemory("building reference");
2610  return(NULL);
2611  }
2612  memset(cur, 0, sizeof(xmlNode));
2613  cur->type = XML_ENTITY_REF_NODE;
2614 
2615  cur->doc = (xmlDoc *)doc;
2616  if (name[0] == '&') {
2617  int len;
2618  name++;
2619  len = xmlStrlen(name);
2620  if (name[len - 1] == ';')
2621  cur->name = xmlStrndup(name, len - 1);
2622  else
2623  cur->name = xmlStrndup(name, len);
2624  } else
2625  cur->name = xmlStrdup(name);
2626 
2627  ent = xmlGetDocEntity(doc, cur->name);
2628  if (ent != NULL) {
2629  cur->content = ent->content;
2630  /*
2631  * The parent pointer in entity is a DTD pointer and thus is NOT
2632  * updated. Not sure if this is 100% correct.
2633  * -George
2634  */
2635  cur->children = (xmlNodePtr) ent;
2636  cur->last = (xmlNodePtr) ent;
2637  }
2638 
2641  return(cur);
2642 }
2643 
2652 xmlNodePtr
2653 xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2654  xmlNodePtr cur;
2655 
2656  cur = xmlNewText(content);
2657  if (cur != NULL) cur->doc = (xmlDoc *)doc;
2658  return(cur);
2659 }
2660 
2669 xmlNodePtr
2670 xmlNewTextLen(const xmlChar *content, int len) {
2671  xmlNodePtr cur;
2672 
2673  /*
2674  * Allocate a new node and fill the fields.
2675  */
2676  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2677  if (cur == NULL) {
2678  xmlTreeErrMemory("building text");
2679  return(NULL);
2680  }
2681  memset(cur, 0, sizeof(xmlNode));
2682  cur->type = XML_TEXT_NODE;
2683 
2684  cur->name = xmlStringText;
2685  if (content != NULL) {
2686  cur->content = xmlStrndup(content, len);
2687  }
2688 
2691  return(cur);
2692 }
2693 
2704 xmlNodePtr
2705 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2706  xmlNodePtr cur;
2707 
2708  cur = xmlNewTextLen(content, len);
2709  if (cur != NULL) cur->doc = doc;
2710  return(cur);
2711 }
2712 
2720 xmlNodePtr
2721 xmlNewComment(const xmlChar *content) {
2722  xmlNodePtr cur;
2723 
2724  /*
2725  * Allocate a new node and fill the fields.
2726  */
2727  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2728  if (cur == NULL) {
2729  xmlTreeErrMemory("building comment");
2730  return(NULL);
2731  }
2732  memset(cur, 0, sizeof(xmlNode));
2733  cur->type = XML_COMMENT_NODE;
2734 
2735  cur->name = xmlStringComment;
2736  if (content != NULL) {
2737  cur->content = xmlStrdup(content);
2738  }
2739 
2742  return(cur);
2743 }
2744 
2754 xmlNodePtr
2755 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2756  xmlNodePtr cur;
2757 
2758  /*
2759  * Allocate a new node and fill the fields.
2760  */
2761  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2762  if (cur == NULL) {
2763  xmlTreeErrMemory("building CDATA");
2764  return(NULL);
2765  }
2766  memset(cur, 0, sizeof(xmlNode));
2768  cur->doc = doc;
2769 
2770  if (content != NULL) {
2771  cur->content = xmlStrndup(content, len);
2772  }
2773 
2776  return(cur);
2777 }
2778 
2787 xmlNodePtr
2789  xmlNodePtr cur;
2790 
2791  cur = xmlNewComment(content);
2792  if (cur != NULL) cur->doc = doc;
2793  return(cur);
2794 }
2795 
2803 void
2805  xmlAttrPtr prop;
2806 
2807  if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2808  return;
2809  if (tree->doc != doc) {
2810  if(tree->type == XML_ELEMENT_NODE) {
2811  prop = tree->properties;
2812  while (prop != NULL) {
2813  if (prop->atype == XML_ATTRIBUTE_ID) {
2814  xmlRemoveID(tree->doc, prop);
2815  }
2816 
2817  prop->doc = doc;
2818  xmlSetListDoc(prop->children, doc);
2819 
2820  /*
2821  * TODO: ID attributes should be also added to the new
2822  * document, but this breaks things like xmlReplaceNode.
2823  * The underlying problem is that xmlRemoveID is only called
2824  * if a node is destroyed, not if it's unlinked.
2825  */
2826 #if 0
2827  if (xmlIsID(doc, tree, prop)) {
2828  xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2829  1);
2830  xmlAddID(NULL, doc, idVal, prop);
2831  }
2832 #endif
2833 
2834  prop = prop->next;
2835  }
2836  }
2837  if (tree->children != NULL)
2838  xmlSetListDoc(tree->children, doc);
2839  tree->doc = doc;
2840  }
2841 }
2842 
2850 void
2852  xmlNodePtr cur;
2853 
2854  if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2855  return;
2856  cur = list;
2857  while (cur != NULL) {
2858  if (cur->doc != doc)
2859  xmlSetTreeDoc(cur, doc);
2860  cur = cur->next;
2861  }
2862 }
2863 
2864 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2865 
2882 xmlNodePtr
2883 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2884  const xmlChar *name, const xmlChar *content) {
2885  xmlNodePtr cur, prev;
2886 
2887  if (parent == NULL) {
2888 #ifdef DEBUG_TREE
2890  "xmlNewChild : parent == NULL\n");
2891 #endif
2892  return(NULL);
2893  }
2894 
2895  if (name == NULL) {
2896 #ifdef DEBUG_TREE
2898  "xmlNewChild : name == NULL\n");
2899 #endif
2900  return(NULL);
2901  }
2902 
2903  /*
2904  * Allocate a new node
2905  */
2906  if (parent->type == XML_ELEMENT_NODE) {
2907  if (ns == NULL)
2908  cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2909  else
2910  cur = xmlNewDocNode(parent->doc, ns, name, content);
2911  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2912  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2913  if (ns == NULL)
2915  else
2917  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2918  cur = xmlNewDocNode( parent->doc, ns, name, content);
2919  } else {
2920  return(NULL);
2921  }
2922  if (cur == NULL) return(NULL);
2923 
2924  /*
2925  * add the new element at the end of the children list.
2926  */
2927  cur->type = XML_ELEMENT_NODE;
2928  cur->parent = parent;
2929  cur->doc = parent->doc;
2930  if (parent->children == NULL) {
2931  parent->children = cur;
2932  parent->last = cur;
2933  } else {
2934  prev = parent->last;
2935  prev->next = cur;
2936  cur->prev = prev;
2937  parent->last = cur;
2938  }
2939 
2940  return(cur);
2941 }
2942 #endif /* LIBXML_TREE_ENABLED */
2943 
2957 static xmlNodePtr
2958 xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2959  xmlAttrPtr attr;
2960 
2961  if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2962  (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2963  ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
2964  return(NULL);
2965 
2966  /* check if an attribute with the same name exists */
2967  if (prop->ns == NULL)
2968  attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2969  else
2970  attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2971 
2972  if (prop->doc != cur->doc) {
2973  xmlSetTreeDoc(prop, cur->doc);
2974  }
2975  prop->parent = cur->parent;
2976  prop->prev = prev;
2977  if (prev != NULL) {
2978  prop->next = prev->next;
2979  prev->next = prop;
2980  if (prop->next)
2981  prop->next->prev = prop;
2982  } else {
2983  prop->next = cur;
2984  cur->prev = prop;
2985  }
2986  if (prop->prev == NULL && prop->parent != NULL)
2987  prop->parent->properties = (xmlAttrPtr) prop;
2988  if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2989  /* different instance, destroy it (attributes must be unique) */
2991  }
2992  return prop;
2993 }
2994 
3009 xmlNodePtr
3011  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3012 #ifdef DEBUG_TREE
3014  "xmlAddNextSibling : cur == NULL\n");
3015 #endif
3016  return(NULL);
3017  }
3018  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3019 #ifdef DEBUG_TREE
3021  "xmlAddNextSibling : elem == NULL\n");
3022 #endif
3023  return(NULL);
3024  }
3025 
3026  if (cur == elem) {
3027 #ifdef DEBUG_TREE
3029  "xmlAddNextSibling : cur == elem\n");
3030 #endif
3031  return(NULL);
3032  }
3033 
3035 
3036  if (elem->type == XML_TEXT_NODE) {
3037  if (cur->type == XML_TEXT_NODE) {
3038  xmlNodeAddContent(cur, elem->content);
3039  xmlFreeNode(elem);
3040  return(cur);
3041  }
3042  if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3043  (cur->name == cur->next->name)) {
3044  xmlChar *tmp;
3045 
3046  tmp = xmlStrdup(elem->content);
3047  tmp = xmlStrcat(tmp, cur->next->content);
3048  xmlNodeSetContent(cur->next, tmp);
3049  xmlFree(tmp);
3050  xmlFreeNode(elem);
3051  return(cur->next);
3052  }
3053  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3054  return xmlAddPropSibling(cur, cur, elem);
3055  }
3056 
3057  if (elem->doc != cur->doc) {
3058  xmlSetTreeDoc(elem, cur->doc);
3059  }
3060  elem->parent = cur->parent;
3061  elem->prev = cur;
3062  elem->next = cur->next;
3063  cur->next = elem;
3064  if (elem->next != NULL)
3065  elem->next->prev = elem;
3066  if ((elem->parent != NULL) && (elem->parent->last == cur))
3067  elem->parent->last = elem;
3068  return(elem);
3069 }
3070 
3071 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3072  defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3073 
3087 xmlNodePtr
3088 xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3089  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3090 #ifdef DEBUG_TREE
3092  "xmlAddPrevSibling : cur == NULL\n");
3093 #endif
3094  return(NULL);
3095  }
3096  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3097 #ifdef DEBUG_TREE
3099  "xmlAddPrevSibling : elem == NULL\n");
3100 #endif
3101  return(NULL);
3102  }
3103 
3104  if (cur == elem) {
3105 #ifdef DEBUG_TREE
3107  "xmlAddPrevSibling : cur == elem\n");
3108 #endif
3109  return(NULL);
3110  }
3111 
3113 
3114  if (elem->type == XML_TEXT_NODE) {
3115  if (cur->type == XML_TEXT_NODE) {
3116  xmlChar *tmp;
3117 
3118  tmp = xmlStrdup(elem->content);
3119  tmp = xmlStrcat(tmp, cur->content);
3120  xmlNodeSetContent(cur, tmp);
3121  xmlFree(tmp);
3122  xmlFreeNode(elem);
3123  return(cur);
3124  }
3125  if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3126  (cur->name == cur->prev->name)) {
3127  xmlNodeAddContent(cur->prev, elem->content);
3128  xmlFreeNode(elem);
3129  return(cur->prev);
3130  }
3131  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3132  return xmlAddPropSibling(cur->prev, cur, elem);
3133  }
3134 
3135  if (elem->doc != cur->doc) {
3136  xmlSetTreeDoc(elem, cur->doc);
3137  }
3138  elem->parent = cur->parent;
3139  elem->next = cur;
3140  elem->prev = cur->prev;
3141  cur->prev = elem;
3142  if (elem->prev != NULL)
3143  elem->prev->next = elem;
3144  if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3145  elem->parent->children = elem;
3146  }
3147  return(elem);
3148 }
3149 #endif /* LIBXML_TREE_ENABLED */
3150 
3163 xmlNodePtr
3166 
3167  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3168 #ifdef DEBUG_TREE
3170  "xmlAddSibling : cur == NULL\n");
3171 #endif
3172  return(NULL);
3173  }
3174 
3175  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3176 #ifdef DEBUG_TREE
3178  "xmlAddSibling : elem == NULL\n");
3179 #endif
3180  return(NULL);
3181  }
3182 
3183  if (cur == elem) {
3184 #ifdef DEBUG_TREE
3186  "xmlAddSibling : cur == elem\n");
3187 #endif
3188  return(NULL);
3189  }
3190 
3191  /*
3192  * Constant time is we can rely on the ->parent->last to find
3193  * the last sibling.
3194  */
3195  if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3196  (cur->parent->children != NULL) &&
3197  (cur->parent->last != NULL) &&
3198  (cur->parent->last->next == NULL)) {
3199  cur = cur->parent->last;
3200  } else {
3201  while (cur->next != NULL) cur = cur->next;
3202  }
3203 
3205 
3206  if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3207  (cur->name == elem->name)) {
3208  xmlNodeAddContent(cur, elem->content);
3209  xmlFreeNode(elem);
3210  return(cur);
3211  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3212  return xmlAddPropSibling(cur, cur, elem);
3213  }
3214 
3215  if (elem->doc != cur->doc) {
3216  xmlSetTreeDoc(elem, cur->doc);
3217  }
3218  parent = cur->parent;
3219  elem->prev = cur;
3220  elem->next = NULL;
3221  elem->parent = parent;
3222  cur->next = elem;
3223  if (parent != NULL)
3224  parent->last = elem;
3225 
3226  return(elem);
3227 }
3228 
3239 xmlNodePtr
3241  xmlNodePtr prev;
3242 
3243  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3244 #ifdef DEBUG_TREE
3246  "xmlAddChildList : parent == NULL\n");
3247 #endif
3248  return(NULL);
3249  }
3250 
3251  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3252 #ifdef DEBUG_TREE
3254  "xmlAddChildList : child == NULL\n");
3255 #endif
3256  return(NULL);
3257  }
3258 
3259  if ((cur->doc != NULL) && (parent->doc != NULL) &&
3260  (cur->doc != parent->doc)) {
3261 #ifdef DEBUG_TREE
3263  "Elements moved to a different document\n");
3264 #endif
3265  }
3266 
3267  /*
3268  * add the first element at the end of the children list.
3269  */
3270 
3271  if (parent->children == NULL) {
3272  parent->children = cur;
3273  } else {
3274  /*
3275  * If cur and parent->last both are TEXT nodes, then merge them.
3276  */
3277  if ((cur->type == XML_TEXT_NODE) &&
3278  (parent->last->type == XML_TEXT_NODE) &&
3279  (cur->name == parent->last->name)) {
3280  xmlNodeAddContent(parent->last, cur->content);
3281  /*
3282  * if it's the only child, nothing more to be done.
3283  */
3284  if (cur->next == NULL) {
3285  xmlFreeNode(cur);
3286  return(parent->last);
3287  }
3288  prev = cur;
3289  cur = cur->next;
3290  xmlFreeNode(prev);
3291  }
3292  prev = parent->last;
3293  prev->next = cur;
3294  cur->prev = prev;
3295  }
3296  while (cur->next != NULL) {
3297  cur->parent = parent;
3298  if (cur->doc != parent->doc) {
3299  xmlSetTreeDoc(cur, parent->doc);
3300  }
3301  cur = cur->next;
3302  }
3303  cur->parent = parent;
3304  /* the parent may not be linked to a doc ! */
3305  if (cur->doc != parent->doc) {
3306  xmlSetTreeDoc(cur, parent->doc);
3307  }
3308  parent->last = cur;
3309 
3310  return(cur);
3311 }
3312 
3325 xmlNodePtr
3327  xmlNodePtr prev;
3328 
3329  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3330 #ifdef DEBUG_TREE
3332  "xmlAddChild : parent == NULL\n");
3333 #endif
3334  return(NULL);
3335  }
3336 
3337  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3338 #ifdef DEBUG_TREE
3340  "xmlAddChild : child == NULL\n");
3341 #endif
3342  return(NULL);
3343  }
3344 
3345  if (parent == cur) {
3346 #ifdef DEBUG_TREE
3348  "xmlAddChild : parent == cur\n");
3349 #endif
3350  return(NULL);
3351  }
3352  /*
3353  * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3354  * cur is then freed.
3355  */
3356  if (cur->type == XML_TEXT_NODE) {
3357  if ((parent->type == XML_TEXT_NODE) &&
3358  (parent->content != NULL) &&
3359  (parent->name == cur->name)) {
3361  xmlFreeNode(cur);
3362  return(parent);
3363  }
3364  if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3365  (parent->last->name == cur->name) &&
3366  (parent->last != cur)) {
3367  xmlNodeAddContent(parent->last, cur->content);
3368  xmlFreeNode(cur);
3369  return(parent->last);
3370  }
3371  }
3372 
3373  /*
3374  * add the new element at the end of the children list.
3375  */
3376  prev = cur->parent;
3377  cur->parent = parent;
3378  if (cur->doc != parent->doc) {
3379  xmlSetTreeDoc(cur, parent->doc);
3380  }
3381  /* this check prevents a loop on tree-traversions if a developer
3382  * tries to add a node to its parent multiple times
3383  */
3384  if (prev == parent)
3385  return(cur);
3386 
3387  /*
3388  * Coalescing
3389  */
3390  if ((parent->type == XML_TEXT_NODE) &&
3391  (parent->content != NULL) &&
3392  (parent != cur)) {
3394  xmlFreeNode(cur);
3395  return(parent);
3396  }
3397  if (cur->type == XML_ATTRIBUTE_NODE) {
3398  if (parent->type != XML_ELEMENT_NODE)
3399  return(NULL);
3400  if (parent->properties != NULL) {
3401  /* check if an attribute with the same name exists */
3402  xmlAttrPtr lastattr;
3403 
3404  if (cur->ns == NULL)
3405  lastattr = xmlHasNsProp(parent, cur->name, NULL);
3406  else
3407  lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3408  if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3409  /* different instance, destroy it (attributes must be unique) */
3410  xmlUnlinkNode((xmlNodePtr) lastattr);
3411  xmlFreeProp(lastattr);
3412  }
3413  if (lastattr == (xmlAttrPtr) cur)
3414  return(cur);
3415 
3416  }
3417  if (parent->properties == NULL) {
3418  parent->properties = (xmlAttrPtr) cur;
3419  } else {
3420  /* find the end */
3421  xmlAttrPtr lastattr = parent->properties;
3422  while (lastattr->next != NULL) {
3423  lastattr = lastattr->next;
3424  }
3425  lastattr->next = (xmlAttrPtr) cur;
3426  ((xmlAttrPtr) cur)->prev = lastattr;
3427  }
3428  } else {
3429  if (parent->children == NULL) {
3430  parent->children = cur;
3431  parent->last = cur;
3432  } else {
3433  prev = parent->last;
3434  prev->next = cur;
3435  cur->prev = prev;
3436  parent->last = cur;
3437  }
3438  }
3439  return(cur);
3440 }
3441 
3449 xmlNodePtr
3450 xmlGetLastChild(const xmlNode *parent) {
3451  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3452 #ifdef DEBUG_TREE
3454  "xmlGetLastChild : parent == NULL\n");
3455 #endif
3456  return(NULL);
3457  }
3458  return(parent->last);
3459 }
3460 
3461 #ifdef LIBXML_TREE_ENABLED
3462 /*
3463  * 5 interfaces from DOM ElementTraversal
3464  */
3465 
3478 unsigned long
3479 xmlChildElementCount(xmlNodePtr parent) {
3480  unsigned long ret = 0;
3481  xmlNodePtr cur = NULL;
3482 
3483  if (parent == NULL)
3484  return(0);
3485  switch (parent->type) {
3486  case XML_ELEMENT_NODE:
3487  case XML_ENTITY_NODE:
3488  case XML_DOCUMENT_NODE:
3491  cur = parent->children;
3492  break;
3493  default:
3494  return(0);
3495  }
3496  while (cur != NULL) {
3497  if (cur->type == XML_ELEMENT_NODE)
3498  ret++;
3499  cur = cur->next;
3500  }
3501  return(ret);
3502 }
3503 
3515 xmlNodePtr
3516 xmlFirstElementChild(xmlNodePtr parent) {
3517  xmlNodePtr cur = NULL;
3518 
3519  if (parent == NULL)
3520  return(NULL);
3521  switch (parent->type) {
3522  case XML_ELEMENT_NODE:
3523  case XML_ENTITY_NODE:
3524  case XML_DOCUMENT_NODE:
3527  cur = parent->children;
3528  break;
3529  default:
3530  return(NULL);
3531  }
3532  while (cur != NULL) {
3533  if (cur->type == XML_ELEMENT_NODE)
3534  return(cur);
3535  cur = cur->next;
3536  }
3537  return(NULL);
3538 }
3539 
3551 xmlNodePtr
3552 xmlLastElementChild(xmlNodePtr parent) {
3553  xmlNodePtr cur = NULL;
3554 
3555  if (parent == NULL)
3556  return(NULL);
3557  switch (parent->type) {
3558  case XML_ELEMENT_NODE:
3559  case XML_ENTITY_NODE:
3560  case XML_DOCUMENT_NODE:
3563  cur = parent->last;
3564  break;
3565  default:
3566  return(NULL);
3567  }
3568  while (cur != NULL) {
3569  if (cur->type == XML_ELEMENT_NODE)
3570  return(cur);
3571  cur = cur->prev;
3572  }
3573  return(NULL);
3574 }
3575 
3588 xmlNodePtr
3589 xmlPreviousElementSibling(xmlNodePtr node) {
3590  if (node == NULL)
3591  return(NULL);
3592  switch (node->type) {
3593  case XML_ELEMENT_NODE:
3594  case XML_TEXT_NODE:
3596  case XML_ENTITY_REF_NODE:
3597  case XML_ENTITY_NODE:
3598  case XML_PI_NODE:
3599  case XML_COMMENT_NODE:
3600  case XML_XINCLUDE_START:
3601  case XML_XINCLUDE_END:
3602  node = node->prev;
3603  break;
3604  default:
3605  return(NULL);
3606  }
3607  while (node != NULL) {
3608  if (node->type == XML_ELEMENT_NODE)
3609  return(node);
3610  node = node->prev;
3611  }
3612  return(NULL);
3613 }
3614 
3627 xmlNodePtr
3628 xmlNextElementSibling(xmlNodePtr node) {
3629  if (node == NULL)
3630  return(NULL);
3631  switch (node->type) {
3632  case XML_ELEMENT_NODE:
3633  case XML_TEXT_NODE:
3635  case XML_ENTITY_REF_NODE:
3636  case XML_ENTITY_NODE:
3637  case XML_PI_NODE:
3638  case XML_COMMENT_NODE:
3639  case XML_DTD_NODE:
3640  case XML_XINCLUDE_START:
3641  case XML_XINCLUDE_END:
3642  node = node->next;
3643  break;
3644  default:
3645  return(NULL);
3646  }
3647  while (node != NULL) {
3648  if (node->type == XML_ELEMENT_NODE)
3649  return(node);
3650  node = node->next;
3651  }
3652  return(NULL);
3653 }
3654 
3655 #endif /* LIBXML_TREE_ENABLED */
3656 
3664 void
3666  xmlNodePtr next;
3667  xmlDictPtr dict = NULL;
3668 
3669  if (cur == NULL) return;
3670  if (cur->type == XML_NAMESPACE_DECL) {
3671  xmlFreeNsList((xmlNsPtr) cur);
3672  return;
3673  }
3674  if ((cur->type == XML_DOCUMENT_NODE) ||
3675 #ifdef LIBXML_DOCB_ENABLED
3676  (cur->type == XML_DOCB_DOCUMENT_NODE) ||
3677 #endif
3678  (cur->type == XML_HTML_DOCUMENT_NODE)) {
3679  xmlFreeDoc((xmlDocPtr) cur);
3680  return;
3681  }
3682  if (cur->doc != NULL) dict = cur->doc->dict;
3683  while (cur != NULL) {
3684  next = cur->next;
3685  if (cur->type != XML_DTD_NODE) {
3686 
3689 
3690  if ((cur->children != NULL) &&
3691  (cur->type != XML_ENTITY_REF_NODE))
3692  xmlFreeNodeList(cur->children);
3693  if (((cur->type == XML_ELEMENT_NODE) ||
3694  (cur->type == XML_XINCLUDE_START) ||
3695  (cur->type == XML_XINCLUDE_END)) &&
3696  (cur->properties != NULL))
3698  if ((cur->type != XML_ELEMENT_NODE) &&
3699  (cur->type != XML_XINCLUDE_START) &&
3700  (cur->type != XML_XINCLUDE_END) &&
3701  (cur->type != XML_ENTITY_REF_NODE) &&
3702  (cur->content != (xmlChar *) &(cur->properties))) {
3703  DICT_FREE(cur->content)
3704  }
3705  if (((cur->type == XML_ELEMENT_NODE) ||
3706  (cur->type == XML_XINCLUDE_START) ||
3707  (cur->type == XML_XINCLUDE_END)) &&
3708  (cur->nsDef != NULL))
3709  xmlFreeNsList(cur->nsDef);
3710 
3711  /*
3712  * When a node is a text node or a comment, it uses a global static
3713  * variable for the name of the node.
3714  * Otherwise the node name might come from the document's
3715  * dictionary
3716  */
3717  if ((cur->name != NULL) &&
3718  (cur->type != XML_TEXT_NODE) &&
3719  (cur->type != XML_COMMENT_NODE))
3720  DICT_FREE(cur->name)
3721  xmlFree(cur);
3722  }
3723  cur = next;
3724  }
3725 }
3726 
3734 void
3735 xmlFreeNode(xmlNodePtr cur) {
3736  xmlDictPtr dict = NULL;
3737 
3738  if (cur == NULL) return;
3739 
3740  /* use xmlFreeDtd for DTD nodes */
3741  if (cur->type == XML_DTD_NODE) {
3742  xmlFreeDtd((xmlDtdPtr) cur);
3743  return;
3744  }
3745  if (cur->type == XML_NAMESPACE_DECL) {
3746  xmlFreeNs((xmlNsPtr) cur);
3747  return;
3748  }
3749  if (cur->type == XML_ATTRIBUTE_NODE) {
3750  xmlFreeProp((xmlAttrPtr) cur);
3751  return;
3752  }
3753 
3756 
3757  if (cur->doc != NULL) dict = cur->doc->dict;
3758 
3759  if (cur->type == XML_ENTITY_DECL) {
3760  xmlEntityPtr ent = (xmlEntityPtr) cur;
3761  DICT_FREE(ent->SystemID);
3762  DICT_FREE(ent->ExternalID);
3763  }
3764  if ((cur->children != NULL) &&
3765  (cur->type != XML_ENTITY_REF_NODE))
3766  xmlFreeNodeList(cur->children);
3767  if (((cur->type == XML_ELEMENT_NODE) ||
3768  (cur->type == XML_XINCLUDE_START) ||
3769  (cur->type == XML_XINCLUDE_END)) &&
3770  (cur->properties != NULL))
3771  xmlFreePropList(cur->properties);
3772  if ((cur->type != XML_ELEMENT_NODE) &&
3773  (cur->content != NULL) &&
3774  (cur->type != XML_ENTITY_REF_NODE) &&
3775  (cur->type != XML_XINCLUDE_END) &&
3776  (cur->type != XML_XINCLUDE_START) &&
3777  (cur->content != (xmlChar *) &(cur->properties))) {
3778  DICT_FREE(cur->content)
3779  }
3780 
3781  /*
3782  * When a node is a text node or a comment, it uses a global static
3783  * variable for the name of the node.
3784  * Otherwise the node name might come from the document's dictionary
3785  */
3786  if ((cur->name != NULL) &&
3787  (cur->type != XML_TEXT_NODE) &&
3788  (cur->type != XML_COMMENT_NODE))
3789  DICT_FREE(cur->name)
3790 
3791  if (((cur->type == XML_ELEMENT_NODE) ||
3792  (cur->type == XML_XINCLUDE_START) ||
3793  (cur->type == XML_XINCLUDE_END)) &&
3794  (cur->nsDef != NULL))
3795  xmlFreeNsList(cur->nsDef);
3796  xmlFree(cur);
3797 }
3798 
3809 void
3811  if (cur == NULL) {
3812 #ifdef DEBUG_TREE
3814  "xmlUnlinkNode : node == NULL\n");
3815 #endif
3816  return;
3817  }
3818  if (cur->type == XML_NAMESPACE_DECL)
3819  return;
3820  if (cur->type == XML_DTD_NODE) {
3821  xmlDocPtr doc;
3822  doc = cur->doc;
3823  if (doc != NULL) {
3824  if (doc->intSubset == (xmlDtdPtr) cur)
3825  doc->intSubset = NULL;
3826  if (doc->extSubset == (xmlDtdPtr) cur)
3827  doc->extSubset = NULL;
3828  }
3829  }
3830  if (cur->type == XML_ENTITY_DECL) {
3831  xmlDocPtr doc;
3832  doc = cur->doc;
3833  if (doc != NULL) {
3834  if (doc->intSubset != NULL) {
3835  if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3836  xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3837  NULL);
3838  if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3839  xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3840  NULL);
3841  }
3842  if (doc->extSubset != NULL) {
3843  if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3844  xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3845  NULL);
3846  if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3847  xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3848  NULL);
3849  }
3850  }
3851  }
3852  if (cur->parent != NULL) {
3854  parent = cur->parent;
3855  if (cur->type == XML_ATTRIBUTE_NODE) {
3856  if (parent->properties == (xmlAttrPtr) cur)
3857  parent->properties = ((xmlAttrPtr) cur)->next;
3858  } else {
3859  if (parent->children == cur)
3860  parent->children = cur->next;
3861  if (parent->last == cur)
3862  parent->last = cur->prev;
3863  }
3864  cur->parent = NULL;
3865  }
3866  if (cur->next != NULL)
3867  cur->next->prev = cur->prev;
3868  if (cur->prev != NULL)
3869  cur->prev->next = cur->next;
3870  cur->next = cur->prev = NULL;
3871 }
3872 
3873 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3874 
3885 xmlNodePtr
3886 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3887  if (old == cur) return(NULL);
3888  if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3889  (old->parent == NULL)) {
3890 #ifdef DEBUG_TREE
3892  "xmlReplaceNode : old == NULL or without parent\n");
3893 #endif
3894  return(NULL);
3895  }
3896  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3897  xmlUnlinkNode(old);
3898  return(old);
3899  }
3900  if (cur == old) {
3901  return(old);
3902  }
3903  if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3904 #ifdef DEBUG_TREE
3906  "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3907 #endif
3908  return(old);
3909  }
3910  if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3911 #ifdef DEBUG_TREE
3913  "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3914 #endif
3915  return(old);
3916  }
3917  xmlUnlinkNode(cur);
3918  xmlSetTreeDoc(cur, old->doc);
3919  cur->parent = old->parent;
3920  cur->next = old->next;
3921  if (cur->next != NULL)
3922  cur->next->prev = cur;
3923  cur->prev = old->prev;
3924  if (cur->prev != NULL)
3925  cur->prev->next = cur;
3926  if (cur->parent != NULL) {
3927  if (cur->type == XML_ATTRIBUTE_NODE) {
3928  if (cur->parent->properties == (xmlAttrPtr)old)
3929  cur->parent->properties = ((xmlAttrPtr) cur);
3930  } else {
3931  if (cur->parent->children == old)
3932  cur->parent->children = cur;
3933  if (cur->parent->last == old)
3934  cur->parent->last = cur;
3935  }
3936  }
3937  old->next = old->prev = NULL;
3938  old->parent = NULL;
3939  return(old);
3940 }
3941 #endif /* LIBXML_TREE_ENABLED */
3942 
3943 /************************************************************************
3944  * *
3945  * Copy operations *
3946  * *
3947  ************************************************************************/
3948 
3957 xmlNsPtr
3959  xmlNsPtr ret;
3960 
3961  if (cur == NULL) return(NULL);
3962  switch (cur->type) {
3963  case XML_LOCAL_NAMESPACE:
3964  ret = xmlNewNs(NULL, cur->href, cur->prefix);
3965  break;
3966  default:
3967 #ifdef DEBUG_TREE
3969  "xmlCopyNamespace: invalid type %d\n", cur->type);
3970 #endif
3971  return(NULL);
3972  }
3973  return(ret);
3974 }
3975 
3984 xmlNsPtr
3986  xmlNsPtr ret = NULL;
3987  xmlNsPtr p = NULL,q;
3988 
3989  while (cur != NULL) {
3990  q = xmlCopyNamespace(cur);
3991  if (p == NULL) {
3992  ret = p = q;
3993  } else {
3994  p->next = q;
3995  p = q;
3996  }
3997  cur = cur->next;
3998  }
3999  return(ret);
4000 }
4001 
4002 static xmlNodePtr
4003 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
4004 
4005 static xmlAttrPtr
4006 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
4007  xmlAttrPtr ret;
4008 
4009  if (cur == NULL) return(NULL);
4010  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4011  return(NULL);
4012  if (target != NULL)
4013  ret = xmlNewDocProp(target->doc, cur->name, NULL);
4014  else if (doc != NULL)
4015  ret = xmlNewDocProp(doc, cur->name, NULL);
4016  else if (cur->parent != NULL)
4017  ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
4018  else if (cur->children != NULL)
4019  ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
4020  else
4021  ret = xmlNewDocProp(NULL, cur->name, NULL);
4022  if (ret == NULL) return(NULL);
4023  ret->parent = target;
4024 
4025  if ((cur->ns != NULL) && (target != NULL)) {
4026  xmlNsPtr ns;
4027 
4028  ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4029  if (ns == NULL) {
4030  /*
4031  * Humm, we are copying an element whose namespace is defined
4032  * out of the new tree scope. Search it in the original tree
4033  * and add it at the top of the new tree
4034  */
4035  ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4036  if (ns != NULL) {
4038  xmlNodePtr pred = NULL;
4039 
4040  while (root->parent != NULL) {
4041  pred = root;
4042  root = root->parent;
4043  }
4044  if (root == (xmlNodePtr) target->doc) {
4045  /* correct possibly cycling above the document elt */
4046  root = pred;
4047  }
4048  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4049  }
4050  } else {
4051  /*
4052  * we have to find something appropriate here since
4053  * we cant be sure, that the namespce we found is identified
4054  * by the prefix
4055  */
4056  if (xmlStrEqual(ns->href, cur->ns->href)) {
4057  /* this is the nice case */
4058  ret->ns = ns;
4059  } else {
4060  /*
4061  * we are in trouble: we need a new reconcilied namespace.
4062  * This is expensive
4063  */
4064  ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
4065  }
4066  }
4067 
4068  } else
4069  ret->ns = NULL;
4070 
4071  if (cur->children != NULL) {
4072  xmlNodePtr tmp;
4073 
4074  ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4075  ret->last = NULL;
4076  tmp = ret->children;
4077  while (tmp != NULL) {
4078  /* tmp->parent = (xmlNodePtr)ret; */
4079  if (tmp->next == NULL)
4080  ret->last = tmp;
4081  tmp = tmp->next;
4082  }
4083  }
4084  /*
4085  * Try to handle IDs
4086  */
4087  if ((target!= NULL) && (cur!= NULL) &&
4088  (target->doc != NULL) && (cur->doc != NULL) &&
4089  (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4090  if (xmlIsID(cur->doc, cur->parent, cur)) {
4091  xmlChar *id;
4092 
4093  id = xmlNodeListGetString(cur->doc, cur->children, 1);
4094  if (id != NULL) {
4095  xmlAddID(NULL, target->doc, id, ret);
4096  xmlFree(id);
4097  }
4098  }
4099  }
4100  return(ret);
4101 }
4102 
4112 xmlAttrPtr
4114  return xmlCopyPropInternal(NULL, target, cur);
4115 }
4116 
4126 xmlAttrPtr
4128  xmlAttrPtr ret = NULL;
4129  xmlAttrPtr p = NULL,q;
4130 
4131  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4132  return(NULL);
4133  while (cur != NULL) {
4134  q = xmlCopyProp(target, cur);
4135  if (q == NULL)
4136  return(NULL);
4137  if (p == NULL) {
4138  ret = p = q;
4139  } else {
4140  p->next = q;
4141  q->prev = p;
4142  p = q;
4143  }
4144  cur = cur->next;
4145  }
4146  return(ret);
4147 }
4148 
4149 /*
4150  * NOTE about the CopyNode operations !
4151  *
4152  * They are split into external and internal parts for one
4153  * tricky reason: namespaces. Doing a direct copy of a node
4154  * say RPM:Copyright without changing the namespace pointer to
4155  * something else can produce stale links. One way to do it is
4156  * to keep a reference counter but this doesn't work as soon
4157  * as one move the element or the subtree out of the scope of
4158  * the existing namespace. The actual solution seems to add
4159  * a copy of the namespace at the top of the copied tree if
4160  * not available in the subtree.
4161  * Hence two functions, the public front-end call the inner ones
4162  * The argument "recursive" normally indicates a recursive copy
4163  * of the node with values 0 (no) and 1 (yes). For XInclude,
4164  * however, we allow a value of 2 to indicate copy properties and
4165  * namespace info, but don't recurse on children.
4166  */
4167 
4168 static xmlNodePtr
4169 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4170  int extended) {
4171  xmlNodePtr ret;
4172 
4173  if (node == NULL) return(NULL);
4174  switch (node->type) {
4175  case XML_TEXT_NODE:
4177  case XML_ELEMENT_NODE:
4179  case XML_ENTITY_REF_NODE:
4180  case XML_ENTITY_NODE:
4181  case XML_PI_NODE:
4182  case XML_COMMENT_NODE:
4183  case XML_XINCLUDE_START:
4184  case XML_XINCLUDE_END:
4185  break;
4186  case XML_ATTRIBUTE_NODE:
4187  return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4188  case XML_NAMESPACE_DECL:
4190 
4191  case XML_DOCUMENT_NODE:
4193 #ifdef LIBXML_DOCB_ENABLED
4194  case XML_DOCB_DOCUMENT_NODE:
4195 #endif
4196 #ifdef LIBXML_TREE_ENABLED
4197  return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4198 #endif /* LIBXML_TREE_ENABLED */
4200  case XML_NOTATION_NODE:
4201  case XML_DTD_NODE:
4202  case XML_ELEMENT_DECL:
4203  case XML_ATTRIBUTE_DECL:
4204  case XML_ENTITY_DECL:
4205  return(NULL);
4206  }
4207 
4208  /*
4209  * Allocate a new node and fill the fields.
4210  */
4211  ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4212  if (ret == NULL) {
4213  xmlTreeErrMemory("copying node");
4214  return(NULL);
4215  }
4216  memset(ret, 0, sizeof(xmlNode));
4217  ret->type = node->type;
4218 
4219  ret->doc = doc;
4220  ret->parent = parent;
4221  if (node->name == xmlStringText)
4222  ret->name = xmlStringText;
4223  else if (node->name == xmlStringTextNoenc)
4224  ret->name = xmlStringTextNoenc;
4225  else if (node->name == xmlStringComment)
4226  ret->name = xmlStringComment;
4227  else if (node->name != NULL) {
4228  if ((doc != NULL) && (doc->dict != NULL))
4229  ret->name = xmlDictLookup(doc->dict, node->name, -1);
4230  else
4231  ret->name = xmlStrdup(node->name);
4232  }
4233  if ((node->type != XML_ELEMENT_NODE) &&
4234  (node->content != NULL) &&
4235  (node->type != XML_ENTITY_REF_NODE) &&
4236  (node->type != XML_XINCLUDE_END) &&
4237  (node->type != XML_XINCLUDE_START)) {
4238  ret->content = xmlStrdup(node->content);
4239  }else{
4240  if (node->type == XML_ELEMENT_NODE)
4241  ret->line = node->line;
4242  }
4243  if (parent != NULL) {
4244  xmlNodePtr tmp;
4245 
4246  /*
4247  * this is a tricky part for the node register thing:
4248  * in case ret does get coalesced in xmlAddChild
4249  * the deregister-node callback is called; so we register ret now already
4250  */
4253 
4254  tmp = xmlAddChild(parent, ret);
4255  /* node could have coalesced */
4256  if (tmp != ret)
4257  return(tmp);
4258  }
4259 
4260  if (!extended)
4261  goto out;
4262  if (((node->type == XML_ELEMENT_NODE) ||
4263  (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4264  ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4265 
4266  if (node->ns != NULL) {
4267  xmlNsPtr ns;
4268 
4269  ns = xmlSearchNs(doc, ret, node->ns->prefix);
4270  if (ns == NULL) {
4271  /*
4272  * Humm, we are copying an element whose namespace is defined
4273  * out of the new tree scope. Search it in the original tree
4274  * and add it at the top of the new tree
4275  */
4276  ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4277  if (ns != NULL) {
4278  xmlNodePtr root = ret;
4279 
4280  while (root->parent != NULL) root = root->parent;
4281  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4282  } else {
4283  ret->ns = xmlNewReconciliedNs(doc, ret, node->ns);
4284  }
4285  } else {
4286  /*
4287  * reference the existing namespace definition in our own tree.
4288  */
4289  ret->ns = ns;
4290  }
4291  }
4292  if (((node->type == XML_ELEMENT_NODE) ||
4293  (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4294  ret->properties = xmlCopyPropList(ret, node->properties);
4295  if (node->type == XML_ENTITY_REF_NODE) {
4296  if ((doc == NULL) || (node->doc != doc)) {
4297  /*
4298  * The copied node will go into a separate document, so
4299  * to avoid dangling references to the ENTITY_DECL node
4300  * we cannot keep the reference. Try to find it in the
4301  * target document.
4302  */
4303  ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4304  } else {
4305  ret->children = node->children;
4306  }
4307  ret->last = ret->children;
4308  } else if ((node->children != NULL) && (extended != 2)) {
4309  ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
4311  }
4312 
4313 out:
4314  /* if parent != NULL we already registered the node above */
4315  if ((parent == NULL) &&
4318  return(ret);
4319 }
4320 
4321 static xmlNodePtr
4322 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4323  xmlNodePtr ret = NULL;
4324  xmlNodePtr p = NULL,q;
4325 
4326  while (node != NULL) {
4327 #ifdef LIBXML_TREE_ENABLED
4328  if (node->type == XML_DTD_NODE ) {
4329  if (doc == NULL) {
4330  node = node->next;
4331  continue;
4332  }
4333  if (doc->intSubset == NULL) {
4334  q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4335  if (q == NULL) return(NULL);
4336  q->doc = doc;
4337  q->parent = parent;
4338  doc->intSubset = (xmlDtdPtr) q;
4339  xmlAddChild(parent, q);
4340  } else {
4341  q = (xmlNodePtr) doc->intSubset;
4342  xmlAddChild(parent, q);
4343  }
4344  } else
4345 #endif /* LIBXML_TREE_ENABLED */
4346  q = xmlStaticCopyNode(node, doc, parent, 1);
4347  if (q == NULL) return(NULL);
4348  if (ret == NULL) {
4349  q->prev = NULL;
4350  ret = p = q;
4351  } else if (p != q) {
4352  /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4353  p->next = q;
4354  q->prev = p;
4355  p = q;
4356  }
4357  node = node->next;
4358  }
4359  return(ret);
4360 }
4361 
4373 xmlNodePtr
4374 xmlCopyNode(xmlNodePtr node, int extended) {
4375  xmlNodePtr ret;
4376 
4377  ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4378  return(ret);
4379 }
4380 
4393 xmlNodePtr
4394 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4395  xmlNodePtr ret;
4396 
4397  ret = xmlStaticCopyNode(node, doc, NULL, extended);
4398  return(ret);
4399 }
4400 
4411  xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4412  return(ret);
4413 }
4414 
4425  xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4426  return(ret);
4427 }
4428 
4429 #if defined(LIBXML_TREE_ENABLED)
4430 
4438 xmlDtdPtr
4439 xmlCopyDtd(xmlDtdPtr dtd) {
4440  xmlDtdPtr ret;
4441  xmlNodePtr cur, p = NULL, q;
4442 
4443  if (dtd == NULL) return(NULL);
4444  ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4445  if (ret == NULL) return(NULL);
4446  if (dtd->entities != NULL)
4447  ret->entities = (void *) xmlCopyEntitiesTable(
4448  (xmlEntitiesTablePtr) dtd->entities);
4449  if (dtd->notations != NULL)
4450  ret->notations = (void *) xmlCopyNotationTable(
4452  if (dtd->elements != NULL)
4453  ret->elements = (void *) xmlCopyElementTable(
4454  (xmlElementTablePtr) dtd->elements);
4455  if (dtd->attributes != NULL)
4456  ret->attributes = (void *) xmlCopyAttributeTable(
4458  if (dtd->pentities != NULL)
4459  ret->pentities = (void *) xmlCopyEntitiesTable(
4461 
4462  cur = dtd->children;
4463  while (cur != NULL) {
4464  q = NULL;
4465 
4466  if (cur->type == XML_ENTITY_DECL) {
4467  xmlEntityPtr tmp = (xmlEntityPtr) cur;
4468  switch (tmp->etype) {
4472  q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4473  break;
4476  q = (xmlNodePtr)
4477  xmlGetParameterEntityFromDtd(ret, tmp->name);
4478  break;
4480  break;
4481  }
4482  } else if (cur->type == XML_ELEMENT_DECL) {
4483  xmlElementPtr tmp = (xmlElementPtr) cur;
4484  q = (xmlNodePtr)
4485  xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4486  } else if (cur->type == XML_ATTRIBUTE_DECL) {
4487  xmlAttributePtr tmp = (xmlAttributePtr) cur;
4488  q = (xmlNodePtr)
4489  xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4490  } else if (cur->type == XML_COMMENT_NODE) {
4491  q = xmlCopyNode(cur, 0);
4492  }
4493 
4494  if (q == NULL) {
4495  cur = cur->next;
4496  continue;
4497  }
4498 
4499  if (p == NULL)
4500  ret->children = q;
4501  else
4502  p->next = q;
4503 
4504  q->prev = p;
4505  q->parent = (xmlNodePtr) ret;
4506  q->next = NULL;
4507  ret->last = q;
4508  p = q;
4509  cur = cur->next;
4510  }
4511 
4512  return(ret);
4513 }
4514 #endif
4515 
4516 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4517 
4527 xmlDocPtr
4528 xmlCopyDoc(xmlDocPtr doc, int recursive) {
4529  xmlDocPtr ret;
4530 
4531  if (doc == NULL) return(NULL);
4532  ret = xmlNewDoc(doc->version);
4533  if (ret == NULL) return(NULL);
4534  if (doc->name != NULL)
4535  ret->name = xmlMemStrdup(doc->name);
4536  if (doc->encoding != NULL)
4537  ret->encoding = xmlStrdup(doc->encoding);
4538  if (doc->URL != NULL)
4539  ret->URL = xmlStrdup(doc->URL);
4540  ret->charset = doc->charset;
4541  ret->compression = doc->compression;
4542  ret->standalone = doc->standalone;
4543  if (!recursive) return(ret);
4544 
4545  ret->last = NULL;
4546  ret->children = NULL;
4547 #ifdef LIBXML_TREE_ENABLED
4548  if (doc->intSubset != NULL) {
4549  ret->intSubset = xmlCopyDtd(doc->intSubset);
4550  if (ret->intSubset == NULL) {
4551  xmlFreeDoc(ret);
4552  return(NULL);
4553  }
4554  xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4555  ret->intSubset->parent = ret;
4556  }
4557 #endif
4558  if (doc->oldNs != NULL)
4559  ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4560  if (doc->children != NULL) {
4561  xmlNodePtr tmp;
4562 
4563  ret->children = xmlStaticCopyNodeList(doc->children, ret,
4564  (xmlNodePtr)ret);
4565  ret->last = NULL;
4566  tmp = ret->children;
4567  while (tmp != NULL) {
4568  if (tmp->next == NULL)
4569  ret->last = tmp;
4570  tmp = tmp->next;
4571  }
4572  }
4573  return(ret);
4574 }
4575 #endif /* LIBXML_TREE_ENABLED */
4576 
4577 /************************************************************************
4578  * *
4579  * Content access functions *
4580  * *
4581  ************************************************************************/
4582 
4593 static long
4594 xmlGetLineNoInternal(const xmlNode *node, int depth)
4595 {
4596  long result = -1;
4597 
4598  if (depth >= 5)
4599  return(-1);
4600 
4601  if (!node)
4602  return result;
4603  if ((node->type == XML_ELEMENT_NODE) ||
4604  (node->type == XML_TEXT_NODE) ||
4605  (node->type == XML_COMMENT_NODE) ||
4606  (node->type == XML_PI_NODE)) {
4607  if (node->line == 65535) {
4608  if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4609  result = (long) (ptrdiff_t) node->psvi;
4610  else if ((node->type == XML_ELEMENT_NODE) &&
4611  (node->children != NULL))
4612  result = xmlGetLineNoInternal(node->children, depth + 1);
4613  else if (node->next != NULL)
4614  result = xmlGetLineNoInternal(node->next, depth + 1);
4615  else if (node->prev != NULL)
4616  result = xmlGetLineNoInternal(node->prev, depth + 1);
4617  }
4618  if ((result == -1) || (result == 65535))
4619  result = (long) node->line;
4620  } else if ((node->prev != NULL) &&
4621  ((node->prev->type == XML_ELEMENT_NODE) ||
4622  (node->prev->type == XML_TEXT_NODE) ||
4623  (node->prev->type == XML_COMMENT_NODE) ||
4624  (node->prev->type == XML_PI_NODE)))
4625  result = xmlGetLineNoInternal(node->prev, depth + 1);
4626  else if ((node->parent != NULL) &&
4627  (node->parent->type == XML_ELEMENT_NODE))
4628  result = xmlGetLineNoInternal(node->parent, depth + 1);
4629 
4630  return result;
4631 }
4632 
4643 long
4644 xmlGetLineNo(const xmlNode *node)
4645 {
4646  return(xmlGetLineNoInternal(node, 0));
4647 }
4648 
4649 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4650 
4659 xmlChar *
4660 xmlGetNodePath(const xmlNode *node)
4661 {
4662  const xmlNode *cur, *tmp, *next;
4663  xmlChar *buffer = NULL, *temp;
4664  size_t buf_len;
4665  xmlChar *buf;
4666  const char *sep;
4667  const char *name;
4668  char nametemp[100];
4669  int occur = 0, generic;
4670 
4671  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4672  return (NULL);
4673 
4674  buf_len = 500;
4675  buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4676  if (buffer == NULL) {
4677  xmlTreeErrMemory("getting node path");
4678  return (NULL);
4679  }
4680  buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4681  if (buf == NULL) {
4682  xmlTreeErrMemory("getting node path");
4683  xmlFree(buffer);
4684  return (NULL);
4685  }
4686 
4687  buffer[0] = 0;
4688  cur = node;
4689  do {
4690  name = "";
4691  sep = "?";
4692  occur = 0;
4693  if ((cur->type == XML_DOCUMENT_NODE) ||
4694  (cur->type == XML_HTML_DOCUMENT_NODE)) {
4695  if (buffer[0] == '/')
4696  break;
4697  sep = "/";
4698  next = NULL;
4699  } else if (cur->type == XML_ELEMENT_NODE) {
4700  generic = 0;
4701  sep = "/";
4702  name = (const char *) cur->name;
4703  if (cur->ns) {
4704  if (cur->ns->prefix != NULL) {
4705  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4706  (char *)cur->ns->prefix, (char *)cur->name);
4707  nametemp[sizeof(nametemp) - 1] = 0;
4708  name = nametemp;
4709  } else {
4710  /*
4711  * We cannot express named elements in the default
4712  * namespace, so use "*".
4713  */
4714  generic = 1;
4715  name = "*";
4716  }
4717  }
4718  next = cur->parent;
4719 
4720  /*
4721  * Thumbler index computation
4722  * TODO: the ocurence test seems bogus for namespaced names
4723  */
4724  tmp = cur->prev;
4725  while (tmp != NULL) {
4726  if ((tmp->type == XML_ELEMENT_NODE) &&
4727  (generic ||
4728  (xmlStrEqual(cur->name, tmp->name) &&
4729  ((tmp->ns == cur->ns) ||
4730  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4731  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4732  occur++;
4733  tmp = tmp->prev;
4734  }
4735  if (occur == 0) {
4736  tmp = cur->next;
4737  while (tmp != NULL && occur == 0) {
4738  if ((tmp->type == XML_ELEMENT_NODE) &&
4739  (generic ||
4740  (xmlStrEqual(cur->name, tmp->name) &&
4741  ((tmp->ns == cur->ns) ||
4742  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4743  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4744  occur++;
4745  tmp = tmp->next;
4746  }
4747  if (occur != 0)
4748  occur = 1;
4749  } else
4750  occur++;
4751  } else if (cur->type == XML_COMMENT_NODE) {
4752  sep = "/";
4753  name = "comment()";
4754  next = cur->parent;
4755 
4756  /*
4757  * Thumbler index computation
4758  */
4759  tmp = cur->prev;
4760  while (tmp != NULL) {
4761  if (tmp->type == XML_COMMENT_NODE)
4762  occur++;
4763  tmp = tmp->prev;
4764  }
4765  if (occur == 0) {
4766  tmp = cur->next;
4767  while (tmp != NULL && occur == 0) {
4768  if (tmp->type == XML_COMMENT_NODE)
4769  occur++;
4770  tmp = tmp->next;
4771  }
4772  if (occur != 0)
4773  occur = 1;
4774  } else
4775  occur++;
4776  } else if ((cur->type == XML_TEXT_NODE) ||
4777  (cur->type == XML_CDATA_SECTION_NODE)) {
4778  sep = "/";
4779  name = "text()";
4780  next = cur->parent;
4781 
4782  /*
4783  * Thumbler index computation
4784  */
4785  tmp = cur->prev;
4786  while (tmp != NULL) {
4787  if ((tmp->type == XML_TEXT_NODE) ||
4788  (tmp->type == XML_CDATA_SECTION_NODE))
4789  occur++;
4790  tmp = tmp->prev;
4791  }
4792  /*
4793  * Evaluate if this is the only text- or CDATA-section-node;
4794  * if yes, then we'll get "text()", otherwise "text()[1]".
4795  */
4796  if (occur == 0) {
4797  tmp = cur->next;
4798  while (tmp != NULL) {
4799  if ((tmp->type == XML_TEXT_NODE) ||
4800  (tmp->type == XML_CDATA_SECTION_NODE))
4801  {
4802  occur = 1;
4803  break;
4804  }
4805  tmp = tmp->next;
4806  }
4807  } else
4808  occur++;
4809  } else if (cur->type == XML_PI_NODE) {
4810  sep = "/";
4811  snprintf(nametemp, sizeof(nametemp) - 1,
4812  "processing-instruction('%s')", (char *)cur->name);
4813  nametemp[sizeof(nametemp) - 1] = 0;
4814  name = nametemp;
4815 
4816  next = cur->parent;
4817 
4818  /*
4819  * Thumbler index computation
4820  */
4821  tmp = cur->prev;
4822  while (tmp != NULL) {
4823  if ((tmp->type == XML_PI_NODE) &&
4824  (xmlStrEqual(cur->name, tmp->name)))
4825  occur++;
4826  tmp = tmp->prev;
4827  }
4828  if (occur == 0) {
4829  tmp = cur->next;
4830  while (tmp != NULL && occur == 0) {
4831  if ((tmp->type == XML_PI_NODE) &&
4832  (xmlStrEqual(cur->name, tmp->name)))
4833  occur++;
4834  tmp = tmp->next;
4835  }
4836  if (occur != 0)
4837  occur = 1;
4838  } else
4839  occur++;
4840 
4841  } else if (cur->type == XML_ATTRIBUTE_NODE) {
4842  sep = "/@";
4843  name = (const char *) (((xmlAttrPtr) cur)->name);
4844  if (cur->ns) {
4845  if (cur->ns->prefix != NULL)
4846  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4847  (char *)cur->ns->prefix, (char *)cur->name);
4848  else
4849  snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4850  (char *)cur->name);
4851  nametemp[sizeof(nametemp) - 1] = 0;
4852  name = nametemp;
4853  }
4854  next = ((xmlAttrPtr) cur)->parent;
4855  } else {
4856  next = cur->parent;
4857  }
4858 
4859  /*
4860  * Make sure there is enough room
4861  */
4862  if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4863  buf_len =
4864  2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4865  temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4866  if (temp == NULL) {
4867  xmlTreeErrMemory("getting node path");
4868  xmlFree(buf);
4869  xmlFree(buffer);
4870  return (NULL);
4871  }
4872  buffer = temp;
4873  temp = (xmlChar *) xmlRealloc(buf, buf_len);
4874  if (temp == NULL) {
4875  xmlTreeErrMemory("getting node path");
4876  xmlFree(buf);
4877  xmlFree(buffer);
4878  return (NULL);
4879  }
4880  buf = temp;
4881  }
4882  if (occur == 0)
4883  snprintf((char *) buf, buf_len, "%s%s%s",
4884  sep, name, (char *) buffer);
4885  else
4886  snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4887  sep, name, occur, (char *) buffer);
4888  snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4889  cur = next;
4890  } while (cur != NULL);
4891  xmlFree(buf);
4892  return (buffer);
4893 }
4894 #endif /* LIBXML_TREE_ENABLED */
4895 
4905 xmlNodePtr
4906 xmlDocGetRootElement(const xmlDoc *doc) {
4907  xmlNodePtr ret;
4908 
4909  if (doc == NULL) return(NULL);
4910  ret = doc->children;
4911  while (ret != NULL) {
4912  if (ret->type == XML_ELEMENT_NODE)
4913  return(ret);
4914  ret = ret->next;
4915  }
4916  return(ret);
4917 }
4918 
4919 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4920 
4931 xmlNodePtr
4932 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4933  xmlNodePtr old = NULL;
4934 
4935  if (doc == NULL) return(NULL);
4936  if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
4937  return(NULL);
4939  xmlSetTreeDoc(root, doc);
4940  root->parent = (xmlNodePtr) doc;
4941  old = doc->children;
4942  while (old != NULL) {
4943  if (old->type == XML_ELEMENT_NODE)
4944  break;
4945  old = old->next;
4946  }
4947  if (old == NULL) {
4948  if (doc->children == NULL) {
4949  doc->children = root;
4950  doc->last = root;
4951  } else {
4952  xmlAddSibling(doc->children, root);
4953  }
4954  } else {
4955  xmlReplaceNode(old, root);
4956  }
4957  return(old);
4958 }
4959 #endif
4960 
4961 #if defined(LIBXML_TREE_ENABLED)
4962 
4970 void
4971 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
4972  xmlNsPtr ns;
4973 
4974  if (cur == NULL) return;
4975  switch(cur->type) {
4976  case XML_TEXT_NODE:
4978  case XML_COMMENT_NODE:
4979  case XML_DOCUMENT_NODE:
4982  case XML_NOTATION_NODE:
4984  case XML_DTD_NODE:
4985  case XML_ELEMENT_DECL:
4986  case XML_ATTRIBUTE_DECL:
4987  case XML_ENTITY_DECL:
4988  case XML_PI_NODE:
4989  case XML_ENTITY_REF_NODE:
4990  case XML_ENTITY_NODE:
4991  case XML_NAMESPACE_DECL:
4992 #ifdef LIBXML_DOCB_ENABLED
4993  case XML_DOCB_DOCUMENT_NODE:
4994 #endif
4995  case XML_XINCLUDE_START:
4996  case XML_XINCLUDE_END:
4997  return;
4998  case XML_ELEMENT_NODE:
4999  case XML_ATTRIBUTE_NODE:
5000  break;
5001  }
5002  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5003  if (ns == NULL)
5004  return;
5005  xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
5006 }
5007 #endif /* LIBXML_TREE_ENABLED */
5008 
5019 xmlChar *
5020 xmlNodeGetLang(const xmlNode *cur) {
5021  xmlChar *lang;
5022 
5023  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
5024  return(NULL);
5025  while (cur != NULL) {
5026  lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
5027  if (lang != NULL)
5028  return(lang);
5029  cur = cur->parent;
5030  }
5031  return(NULL);
5032 }
5033 
5034 
5035 #ifdef LIBXML_TREE_ENABLED
5036 
5044 void
5045 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
5046  xmlNsPtr ns;
5047 
5048  if (cur == NULL) return;
5049  switch(cur->type) {
5050  case XML_TEXT_NODE:
5052  case XML_COMMENT_NODE:
5053  case XML_DOCUMENT_NODE:
5056  case XML_NOTATION_NODE:
5058  case XML_DTD_NODE:
5059  case XML_ELEMENT_DECL:
5060  case XML_ATTRIBUTE_DECL:
5061  case XML_ENTITY_DECL:
5062  case XML_PI_NODE:
5063  case XML_ENTITY_REF_NODE:
5064  case XML_ENTITY_NODE:
5065  case XML_NAMESPACE_DECL:
5066  case XML_XINCLUDE_START:
5067  case XML_XINCLUDE_END:
5068 #ifdef LIBXML_DOCB_ENABLED
5069  case XML_DOCB_DOCUMENT_NODE:
5070 #endif
5071  return;
5072  case XML_ELEMENT_NODE:
5073  case XML_ATTRIBUTE_NODE:
5074  break;
5075  }
5076  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5077  if (ns == NULL)
5078  return;
5079  switch (val) {
5080  case 0:
5081  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
5082  break;
5083  case 1:
5084  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
5085  break;
5086  }
5087 }
5088 #endif /* LIBXML_TREE_ENABLED */
5089 
5100 int
5101 xmlNodeGetSpacePreserve(const xmlNode *cur) {
5102  xmlChar *space;
5103 
5104  if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5105  return(-1);
5106  while (cur != NULL) {
5107  space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
5108  if (space != NULL) {
5109  if (xmlStrEqual(space, BAD_CAST "preserve")) {
5110  xmlFree(space);
5111  return(1);
5112  }
5113  if (xmlStrEqual(space, BAD_CAST "default")) {
5114  xmlFree(space);
5115  return(0);
5116  }
5117  xmlFree(space);
5118  }
5119  cur = cur->parent;
5120  }
5121  return(-1);
5122 }
5123 
5124 #ifdef LIBXML_TREE_ENABLED
5125 
5132 void
5133 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
5134  xmlDocPtr doc;
5135  xmlDictPtr dict;
5136  const xmlChar *freeme = NULL;
5137 
5138  if (cur == NULL) return;
5139  if (name == NULL) return;
5140  switch(cur->type) {
5141  case XML_TEXT_NODE:
5143  case XML_COMMENT_NODE:
5146  case XML_NOTATION_NODE:
5148  case XML_NAMESPACE_DECL:
5149  case XML_XINCLUDE_START:
5150  case XML_XINCLUDE_END:
5151 #ifdef LIBXML_DOCB_ENABLED
5152  case XML_DOCB_DOCUMENT_NODE:
5153 #endif
5154  return;
5155  case XML_ELEMENT_NODE:
5156  case XML_ATTRIBUTE_NODE:
5157  case XML_PI_NODE:
5158  case XML_ENTITY_REF_NODE:
5159  case XML_ENTITY_NODE:
5160  case XML_DTD_NODE:
5161  case XML_DOCUMENT_NODE:
5162  case XML_ELEMENT_DECL:
5163  case XML_ATTRIBUTE_DECL:
5164  case XML_ENTITY_DECL:
5165  break;
5166  }
5167  doc = cur->doc;
5168  if (doc != NULL)
5169  dict = doc->dict;
5170  else
5171  dict = NULL;
5172  if (dict != NULL) {
5173  if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5174  freeme = cur->name;
5175  cur->name = xmlDictLookup(dict, name, -1);
5176  } else {
5177  if (cur->name != NULL)
5178  freeme = cur->name;
5179  cur->name = xmlStrdup(name);
5180  }
5181 
5182  if (freeme)
5183  xmlFree((xmlChar *) freeme);
5184 }
5185 #endif
5186 
5187 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
5188 
5196 void
5197 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
5198  xmlNsPtr ns;
5199  xmlChar* fixed;
5200 
5201  if (cur == NULL) return;
5202  switch(cur->type) {
5203  case XML_TEXT_NODE:
5205  case XML_COMMENT_NODE:
5208  case XML_NOTATION_NODE:
5209  case XML_DTD_NODE:
5210  case XML_ELEMENT_DECL:
5211  case XML_ATTRIBUTE_DECL:
5212  case XML_ENTITY_DECL:
5213  case XML_PI_NODE:
5214  case XML_ENTITY_REF_NODE:
5215  case XML_ENTITY_NODE:
5216  case XML_NAMESPACE_DECL:
5217  case XML_XINCLUDE_START:
5218  case XML_XINCLUDE_END:
5219  return;
5220  case XML_ELEMENT_NODE:
5221  case XML_ATTRIBUTE_NODE:
5222  break;
5223  case XML_DOCUMENT_NODE:
5224 #ifdef LIBXML_DOCB_ENABLED
5225  case XML_DOCB_DOCUMENT_NODE:
5226 #endif
5227  case XML_HTML_DOCUMENT_NODE: {
5228  xmlDocPtr doc = (xmlDocPtr) cur;
5229 
5230  if (doc->URL != NULL)
5231  xmlFree((xmlChar *) doc->URL);
5232  if (uri == NULL)
5233  doc->URL = NULL;
5234  else
5235  doc->URL = xmlPathToURI(uri);
5236  return;
5237  }
5238  }
5239 
5240  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5241  if (ns == NULL)
5242  return;
5243  fixed = xmlPathToURI(uri);
5244  if (fixed != NULL) {
5245  xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
5246  xmlFree(fixed);
5247  } else {
5248  xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5249  }
5250 }
5251 #endif /* LIBXML_TREE_ENABLED */
5252 
5270 xmlChar *
5271 xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) {
5272  xmlChar *oldbase = NULL;
5273  xmlChar *base, *newbase;
5274 
5275  if ((cur == NULL) && (doc == NULL))
5276  return(NULL);
5277  if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
5278  return(NULL);
5279  if (doc == NULL) doc = cur->doc;
5280  if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5281  cur = doc->children;
5282  while ((cur != NULL) && (cur->name != NULL)) {
5283  if (cur->type != XML_ELEMENT_NODE) {
5284  cur = cur->next;
5285  continue;
5286  }
5287  if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5288  cur = cur->children;
5289  continue;
5290  }
5291  if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5292  cur = cur->children;
5293  continue;
5294  }
5295  if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5296  return(xmlGetProp(cur, BAD_CAST "href"));
5297  }
5298  cur = cur->next;
5299  }
5300  return(NULL);
5301  }
5302  while (cur != NULL) {
5303  if (cur->type == XML_ENTITY_DECL) {
5304  xmlEntityPtr ent = (xmlEntityPtr) cur;
5305  return(xmlStrdup(ent->URI));
5306  }
5307  if (cur->type == XML_ELEMENT_NODE) {
5308  base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
5309  if (base != NULL) {
5310  if (oldbase != NULL) {
5311  newbase = xmlBuildURI(oldbase, base);
5312  if (newbase != NULL) {
5313  xmlFree(oldbase);
5314  xmlFree(base);
5315  oldbase = newbase;
5316  } else {
5317  xmlFree(oldbase);
5318  xmlFree(base);
5319  return(NULL);
5320  }
5321  } else {
5322  oldbase = base;
5323  }
5324  if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5325  (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5326  (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5327  return(oldbase);
5328  }
5329  }
5330  cur = cur->parent;
5331  }
5332  if ((doc != NULL) && (doc->URL != NULL)) {
5333  if (oldbase == NULL)
5334  return(xmlStrdup(doc->URL));
5335  newbase = xmlBuildURI(oldbase, doc->URL);
5336  xmlFree(oldbase);
5337  return(newbase);
5338  }
5339  return(oldbase);
5340 }
5341 
5355 int
5357 {
5358  xmlBufPtr buf;
5359  int ret;
5360 
5361  if ((cur == NULL) || (buffer == NULL)) return(-1);
5363  ret = xmlBufGetNodeContent(buf, cur);
5365  if ((ret < 0) || (buffer == NULL))
5366  return(-1);
5367  return(0);
5368 }
5369 
5383 int
5385 {
5386  if ((cur == NULL) || (buf == NULL)) return(-1);
5387  switch (cur->type) {
5389  case XML_TEXT_NODE:
5390  xmlBufCat(buf, cur->content);
5391  break;
5393  case XML_ELEMENT_NODE:{
5394  const xmlNode *tmp = cur;
5395 
5396  while (tmp != NULL) {
5397  switch (tmp->type) {
5399  case XML_TEXT_NODE:
5400  if (tmp->content != NULL)
5401  xmlBufCat(buf, tmp->content);
5402  break;
5403  case XML_ENTITY_REF_NODE:
5404  xmlBufGetNodeContent(buf, tmp);
5405  break;
5406  default:
5407  break;
5408  }
5409  /*
5410  * Skip to next node
5411  */
5412  if (tmp->children != NULL) {
5413  if (tmp->children->type != XML_ENTITY_DECL) {
5414  tmp = tmp->children;
5415  continue;
5416  }
5417  }
5418  if (tmp == cur)
5419  break;
5420 
5421  if (tmp->next != NULL) {
5422  tmp = tmp->next;
5423  continue;
5424  }
5425 
5426  do {
5427  tmp = tmp->parent;
5428  if (tmp == NULL)
5429  break;
5430  if (tmp == cur) {
5431  tmp = NULL;
5432  break;
5433  }
5434  if (tmp->next != NULL) {
5435  tmp = tmp->next;
5436  break;
5437  }
5438  } while (tmp != NULL);
5439  }
5440  break;
5441  }
5442  case XML_ATTRIBUTE_NODE:{
5443  xmlAttrPtr attr = (xmlAttrPtr) cur;
5444  xmlNodePtr tmp = attr->children;
5445 
5446  while (tmp != NULL) {
5447  if (tmp->type == XML_TEXT_NODE)
5448  xmlBufCat(buf, tmp->content);
5449  else
5450  xmlBufGetNodeContent(buf, tmp);
5451  tmp = tmp->next;
5452  }
5453  break;
5454  }
5455  case XML_COMMENT_NODE:
5456  case XML_PI_NODE:
5457  xmlBufCat(buf, cur->content);
5458  break;
5459<