Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xml2/tree.c
4393 views
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
* [email protected]
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
#include <ctype.h>
25
#include <stdlib.h>
26
27
#ifdef LIBXML_ZLIB_ENABLED
28
#include <zlib.h>
29
#endif
30
31
#include <libxml/tree.h>
32
#include <libxml/xmlmemory.h>
33
#include <libxml/parser.h>
34
#include <libxml/uri.h>
35
#include <libxml/entities.h>
36
#include <libxml/xmlerror.h>
37
#include <libxml/parserInternals.h>
38
#ifdef LIBXML_HTML_ENABLED
39
#include <libxml/HTMLtree.h>
40
#endif
41
#ifdef LIBXML_DEBUG_ENABLED
42
#include <libxml/debugXML.h>
43
#endif
44
45
#include "private/buf.h"
46
#include "private/entities.h"
47
#include "private/error.h"
48
#include "private/tree.h"
49
50
int __xmlRegisterCallbacks = 0;
51
52
/************************************************************************
53
* *
54
* Forward declarations *
55
* *
56
************************************************************************/
57
58
static xmlNsPtr
59
xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
60
61
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
62
63
/************************************************************************
64
* *
65
* Tree memory error handler *
66
* *
67
************************************************************************/
68
/**
69
* xmlTreeErrMemory:
70
* @extra: extra information
71
*
72
* Handle an out of memory condition
73
*/
74
static void
75
xmlTreeErrMemory(const char *extra)
76
{
77
__xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
78
}
79
80
/**
81
* xmlTreeErr:
82
* @code: the error number
83
* @extra: extra information
84
*
85
* Handle an out of memory condition
86
*/
87
static void
88
xmlTreeErr(int code, xmlNodePtr node, const char *extra)
89
{
90
const char *msg = NULL;
91
92
switch(code) {
93
case XML_TREE_INVALID_HEX:
94
msg = "invalid hexadecimal character value\n";
95
break;
96
case XML_TREE_INVALID_DEC:
97
msg = "invalid decimal character value\n";
98
break;
99
case XML_TREE_UNTERMINATED_ENTITY:
100
msg = "unterminated entity reference %15s\n";
101
break;
102
case XML_TREE_NOT_UTF8:
103
msg = "string is not in UTF-8\n";
104
break;
105
default:
106
msg = "unexpected error number\n";
107
}
108
__xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
109
}
110
111
/************************************************************************
112
* *
113
* A few static variables and macros *
114
* *
115
************************************************************************/
116
/* #undef xmlStringText */
117
const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
118
/* #undef xmlStringTextNoenc */
119
const xmlChar xmlStringTextNoenc[] =
120
{ 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
121
/* #undef xmlStringComment */
122
const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
123
124
static int xmlCompressMode = 0;
125
static int xmlCheckDTD = 1;
126
127
#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
128
xmlNodePtr ulccur = (n)->children; \
129
if (ulccur == NULL) { \
130
(n)->last = NULL; \
131
} else { \
132
while (ulccur->next != NULL) { \
133
ulccur->parent = (n); \
134
ulccur = ulccur->next; \
135
} \
136
ulccur->parent = (n); \
137
(n)->last = ulccur; \
138
}}
139
140
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
141
(str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
142
143
/************************************************************************
144
* *
145
* Functions to move to entities.c once the *
146
* API freeze is smoothen and they can be made public. *
147
* *
148
************************************************************************/
149
#include <libxml/hash.h>
150
151
#ifdef LIBXML_TREE_ENABLED
152
/**
153
* xmlGetEntityFromDtd:
154
* @dtd: A pointer to the DTD to search
155
* @name: The entity name
156
*
157
* Do an entity lookup in the DTD entity hash table and
158
* return the corresponding entity, if found.
159
*
160
* Returns A pointer to the entity structure or NULL if not found.
161
*/
162
static xmlEntityPtr
163
xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
164
xmlEntitiesTablePtr table;
165
166
if((dtd != NULL) && (dtd->entities != NULL)) {
167
table = (xmlEntitiesTablePtr) dtd->entities;
168
return((xmlEntityPtr) xmlHashLookup(table, name));
169
/* return(xmlGetEntityFromTable(table, name)); */
170
}
171
return(NULL);
172
}
173
/**
174
* xmlGetParameterEntityFromDtd:
175
* @dtd: A pointer to the DTD to search
176
* @name: The entity name
177
*
178
* Do an entity lookup in the DTD parameter entity hash table and
179
* return the corresponding entity, if found.
180
*
181
* Returns A pointer to the entity structure or NULL if not found.
182
*/
183
static xmlEntityPtr
184
xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
185
xmlEntitiesTablePtr table;
186
187
if ((dtd != NULL) && (dtd->pentities != NULL)) {
188
table = (xmlEntitiesTablePtr) dtd->pentities;
189
return((xmlEntityPtr) xmlHashLookup(table, name));
190
/* return(xmlGetEntityFromTable(table, name)); */
191
}
192
return(NULL);
193
}
194
#endif /* LIBXML_TREE_ENABLED */
195
196
/************************************************************************
197
* *
198
* QName handling helper *
199
* *
200
************************************************************************/
201
202
/**
203
* xmlBuildQName:
204
* @ncname: the Name
205
* @prefix: the prefix
206
* @memory: preallocated memory
207
* @len: preallocated memory length
208
*
209
* Builds the QName @prefix:@ncname in @memory if there is enough space
210
* and prefix is not NULL nor empty, otherwise allocate a new string.
211
* If prefix is NULL or empty it returns ncname.
212
*
213
* Returns the new string which must be freed by the caller if different from
214
* @memory and @ncname or NULL in case of error
215
*/
216
xmlChar *
217
xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
218
xmlChar *memory, int len) {
219
int lenn, lenp;
220
xmlChar *ret;
221
222
if (ncname == NULL) return(NULL);
223
if (prefix == NULL) return((xmlChar *) ncname);
224
225
lenn = strlen((char *) ncname);
226
lenp = strlen((char *) prefix);
227
228
if ((memory == NULL) || (len < lenn + lenp + 2)) {
229
ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
230
if (ret == NULL) {
231
xmlTreeErrMemory("building QName");
232
return(NULL);
233
}
234
} else {
235
ret = memory;
236
}
237
memcpy(&ret[0], prefix, lenp);
238
ret[lenp] = ':';
239
memcpy(&ret[lenp + 1], ncname, lenn);
240
ret[lenn + lenp + 1] = 0;
241
return(ret);
242
}
243
244
/**
245
* xmlSplitQName2:
246
* @name: the full QName
247
* @prefix: a xmlChar **
248
*
249
* parse an XML qualified name string
250
*
251
* [NS 5] QName ::= (Prefix ':')? LocalPart
252
*
253
* [NS 6] Prefix ::= NCName
254
*
255
* [NS 7] LocalPart ::= NCName
256
*
257
* Returns NULL if the name doesn't have a prefix. Otherwise, returns the
258
* local part, and prefix is updated to get the Prefix. Both the return value
259
* and the prefix must be freed by the caller.
260
*/
261
xmlChar *
262
xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
263
int len = 0;
264
xmlChar *ret = NULL;
265
266
if (prefix == NULL) return(NULL);
267
*prefix = NULL;
268
if (name == NULL) return(NULL);
269
270
#ifndef XML_XML_NAMESPACE
271
/* xml: prefix is not really a namespace */
272
if ((name[0] == 'x') && (name[1] == 'm') &&
273
(name[2] == 'l') && (name[3] == ':'))
274
return(NULL);
275
#endif
276
277
/* nasty but valid */
278
if (name[0] == ':')
279
return(NULL);
280
281
/*
282
* we are not trying to validate but just to cut, and yes it will
283
* work even if this is as set of UTF-8 encoded chars
284
*/
285
while ((name[len] != 0) && (name[len] != ':'))
286
len++;
287
288
if (name[len] == 0)
289
return(NULL);
290
291
*prefix = xmlStrndup(name, len);
292
if (*prefix == NULL) {
293
xmlTreeErrMemory("QName split");
294
return(NULL);
295
}
296
ret = xmlStrdup(&name[len + 1]);
297
if (ret == NULL) {
298
xmlTreeErrMemory("QName split");
299
if (*prefix != NULL) {
300
xmlFree(*prefix);
301
*prefix = NULL;
302
}
303
return(NULL);
304
}
305
306
return(ret);
307
}
308
309
/**
310
* xmlSplitQName3:
311
* @name: the full QName
312
* @len: an int *
313
*
314
* parse an XML qualified name string,i
315
*
316
* returns NULL if it is not a Qualified Name, otherwise, update len
317
* with the length in byte of the prefix and return a pointer
318
* to the start of the name without the prefix
319
*/
320
321
const xmlChar *
322
xmlSplitQName3(const xmlChar *name, int *len) {
323
int l = 0;
324
325
if (name == NULL) return(NULL);
326
if (len == NULL) return(NULL);
327
328
/* nasty but valid */
329
if (name[0] == ':')
330
return(NULL);
331
332
/*
333
* we are not trying to validate but just to cut, and yes it will
334
* work even if this is as set of UTF-8 encoded chars
335
*/
336
while ((name[l] != 0) && (name[l] != ':'))
337
l++;
338
339
if (name[l] == 0)
340
return(NULL);
341
342
*len = l;
343
344
return(&name[l+1]);
345
}
346
347
/************************************************************************
348
* *
349
* Check Name, NCName and QName strings *
350
* *
351
************************************************************************/
352
353
#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
354
355
/**
356
* xmlValidateNCName:
357
* @value: the value to check
358
* @space: allow spaces in front and end of the string
359
*
360
* Check that a value conforms to the lexical space of NCName
361
*
362
* Returns 0 if this validates, a positive error code number otherwise
363
* and -1 in case of internal or API error.
364
*/
365
int
366
xmlValidateNCName(const xmlChar *value, int space) {
367
const xmlChar *cur = value;
368
int c,l;
369
370
if (value == NULL)
371
return(-1);
372
373
/*
374
* First quick algorithm for ASCII range
375
*/
376
if (space)
377
while (IS_BLANK_CH(*cur)) cur++;
378
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
379
(*cur == '_'))
380
cur++;
381
else
382
goto try_complex;
383
while (((*cur >= 'a') && (*cur <= 'z')) ||
384
((*cur >= 'A') && (*cur <= 'Z')) ||
385
((*cur >= '0') && (*cur <= '9')) ||
386
(*cur == '_') || (*cur == '-') || (*cur == '.'))
387
cur++;
388
if (space)
389
while (IS_BLANK_CH(*cur)) cur++;
390
if (*cur == 0)
391
return(0);
392
393
try_complex:
394
/*
395
* Second check for chars outside the ASCII range
396
*/
397
cur = value;
398
c = CUR_SCHAR(cur, l);
399
if (space) {
400
while (IS_BLANK(c)) {
401
cur += l;
402
c = CUR_SCHAR(cur, l);
403
}
404
}
405
if ((!IS_LETTER(c)) && (c != '_'))
406
return(1);
407
cur += l;
408
c = CUR_SCHAR(cur, l);
409
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
410
(c == '-') || (c == '_') || IS_COMBINING(c) ||
411
IS_EXTENDER(c)) {
412
cur += l;
413
c = CUR_SCHAR(cur, l);
414
}
415
if (space) {
416
while (IS_BLANK(c)) {
417
cur += l;
418
c = CUR_SCHAR(cur, l);
419
}
420
}
421
if (c != 0)
422
return(1);
423
424
return(0);
425
}
426
427
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
428
/**
429
* xmlValidateQName:
430
* @value: the value to check
431
* @space: allow spaces in front and end of the string
432
*
433
* Check that a value conforms to the lexical space of QName
434
*
435
* Returns 0 if this validates, a positive error code number otherwise
436
* and -1 in case of internal or API error.
437
*/
438
int
439
xmlValidateQName(const xmlChar *value, int space) {
440
const xmlChar *cur = value;
441
int c,l;
442
443
if (value == NULL)
444
return(-1);
445
/*
446
* First quick algorithm for ASCII range
447
*/
448
if (space)
449
while (IS_BLANK_CH(*cur)) cur++;
450
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
451
(*cur == '_'))
452
cur++;
453
else
454
goto try_complex;
455
while (((*cur >= 'a') && (*cur <= 'z')) ||
456
((*cur >= 'A') && (*cur <= 'Z')) ||
457
((*cur >= '0') && (*cur <= '9')) ||
458
(*cur == '_') || (*cur == '-') || (*cur == '.'))
459
cur++;
460
if (*cur == ':') {
461
cur++;
462
if (((*cur >= 'a') && (*cur <= 'z')) ||
463
((*cur >= 'A') && (*cur <= 'Z')) ||
464
(*cur == '_'))
465
cur++;
466
else
467
goto try_complex;
468
while (((*cur >= 'a') && (*cur <= 'z')) ||
469
((*cur >= 'A') && (*cur <= 'Z')) ||
470
((*cur >= '0') && (*cur <= '9')) ||
471
(*cur == '_') || (*cur == '-') || (*cur == '.'))
472
cur++;
473
}
474
if (space)
475
while (IS_BLANK_CH(*cur)) cur++;
476
if (*cur == 0)
477
return(0);
478
479
try_complex:
480
/*
481
* Second check for chars outside the ASCII range
482
*/
483
cur = value;
484
c = CUR_SCHAR(cur, l);
485
if (space) {
486
while (IS_BLANK(c)) {
487
cur += l;
488
c = CUR_SCHAR(cur, l);
489
}
490
}
491
if ((!IS_LETTER(c)) && (c != '_'))
492
return(1);
493
cur += l;
494
c = CUR_SCHAR(cur, l);
495
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
496
(c == '-') || (c == '_') || IS_COMBINING(c) ||
497
IS_EXTENDER(c)) {
498
cur += l;
499
c = CUR_SCHAR(cur, l);
500
}
501
if (c == ':') {
502
cur += l;
503
c = CUR_SCHAR(cur, l);
504
if ((!IS_LETTER(c)) && (c != '_'))
505
return(1);
506
cur += l;
507
c = CUR_SCHAR(cur, l);
508
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
509
(c == '-') || (c == '_') || IS_COMBINING(c) ||
510
IS_EXTENDER(c)) {
511
cur += l;
512
c = CUR_SCHAR(cur, l);
513
}
514
}
515
if (space) {
516
while (IS_BLANK(c)) {
517
cur += l;
518
c = CUR_SCHAR(cur, l);
519
}
520
}
521
if (c != 0)
522
return(1);
523
return(0);
524
}
525
526
/**
527
* xmlValidateName:
528
* @value: the value to check
529
* @space: allow spaces in front and end of the string
530
*
531
* Check that a value conforms to the lexical space of Name
532
*
533
* Returns 0 if this validates, a positive error code number otherwise
534
* and -1 in case of internal or API error.
535
*/
536
int
537
xmlValidateName(const xmlChar *value, int space) {
538
const xmlChar *cur = value;
539
int c,l;
540
541
if (value == NULL)
542
return(-1);
543
/*
544
* First quick algorithm for ASCII range
545
*/
546
if (space)
547
while (IS_BLANK_CH(*cur)) cur++;
548
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
549
(*cur == '_') || (*cur == ':'))
550
cur++;
551
else
552
goto try_complex;
553
while (((*cur >= 'a') && (*cur <= 'z')) ||
554
((*cur >= 'A') && (*cur <= 'Z')) ||
555
((*cur >= '0') && (*cur <= '9')) ||
556
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
557
cur++;
558
if (space)
559
while (IS_BLANK_CH(*cur)) cur++;
560
if (*cur == 0)
561
return(0);
562
563
try_complex:
564
/*
565
* Second check for chars outside the ASCII range
566
*/
567
cur = value;
568
c = CUR_SCHAR(cur, l);
569
if (space) {
570
while (IS_BLANK(c)) {
571
cur += l;
572
c = CUR_SCHAR(cur, l);
573
}
574
}
575
if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
576
return(1);
577
cur += l;
578
c = CUR_SCHAR(cur, l);
579
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
580
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
581
cur += l;
582
c = CUR_SCHAR(cur, l);
583
}
584
if (space) {
585
while (IS_BLANK(c)) {
586
cur += l;
587
c = CUR_SCHAR(cur, l);
588
}
589
}
590
if (c != 0)
591
return(1);
592
return(0);
593
}
594
595
/**
596
* xmlValidateNMToken:
597
* @value: the value to check
598
* @space: allow spaces in front and end of the string
599
*
600
* Check that a value conforms to the lexical space of NMToken
601
*
602
* Returns 0 if this validates, a positive error code number otherwise
603
* and -1 in case of internal or API error.
604
*/
605
int
606
xmlValidateNMToken(const xmlChar *value, int space) {
607
const xmlChar *cur = value;
608
int c,l;
609
610
if (value == NULL)
611
return(-1);
612
/*
613
* First quick algorithm for ASCII range
614
*/
615
if (space)
616
while (IS_BLANK_CH(*cur)) cur++;
617
if (((*cur >= 'a') && (*cur <= 'z')) ||
618
((*cur >= 'A') && (*cur <= 'Z')) ||
619
((*cur >= '0') && (*cur <= '9')) ||
620
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
621
cur++;
622
else
623
goto try_complex;
624
while (((*cur >= 'a') && (*cur <= 'z')) ||
625
((*cur >= 'A') && (*cur <= 'Z')) ||
626
((*cur >= '0') && (*cur <= '9')) ||
627
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
628
cur++;
629
if (space)
630
while (IS_BLANK_CH(*cur)) cur++;
631
if (*cur == 0)
632
return(0);
633
634
try_complex:
635
/*
636
* Second check for chars outside the ASCII range
637
*/
638
cur = value;
639
c = CUR_SCHAR(cur, l);
640
if (space) {
641
while (IS_BLANK(c)) {
642
cur += l;
643
c = CUR_SCHAR(cur, l);
644
}
645
}
646
if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
647
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
648
return(1);
649
cur += l;
650
c = CUR_SCHAR(cur, l);
651
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
652
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
653
cur += l;
654
c = CUR_SCHAR(cur, l);
655
}
656
if (space) {
657
while (IS_BLANK(c)) {
658
cur += l;
659
c = CUR_SCHAR(cur, l);
660
}
661
}
662
if (c != 0)
663
return(1);
664
return(0);
665
}
666
#endif /* LIBXML_TREE_ENABLED */
667
668
/************************************************************************
669
* *
670
* Allocation and deallocation of basic structures *
671
* *
672
************************************************************************/
673
674
/**
675
* xmlSetBufferAllocationScheme:
676
* @scheme: allocation method to use
677
*
678
* Set the buffer allocation method. Types are
679
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
680
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
681
* improves performance
682
*/
683
void
684
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
685
if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
686
(scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
687
(scheme == XML_BUFFER_ALLOC_HYBRID))
688
xmlBufferAllocScheme = scheme;
689
}
690
691
/**
692
* xmlGetBufferAllocationScheme:
693
*
694
* Types are
695
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
696
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
697
* improves performance
698
* XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
699
* in normal usage, and doubleit on large strings to avoid
700
* pathological performance.
701
*
702
* Returns the current allocation scheme
703
*/
704
xmlBufferAllocationScheme
705
xmlGetBufferAllocationScheme(void) {
706
return(xmlBufferAllocScheme);
707
}
708
709
/**
710
* xmlNewNs:
711
* @node: the element carrying the namespace
712
* @href: the URI associated
713
* @prefix: the prefix for the namespace
714
*
715
* Creation of a new Namespace. This function will refuse to create
716
* a namespace with a similar prefix than an existing one present on this
717
* node.
718
* Note that for a default namespace, @prefix should be NULL.
719
*
720
* We use href==NULL in the case of an element creation where the namespace
721
* was not defined.
722
*
723
* Returns a new namespace pointer or NULL
724
*/
725
xmlNsPtr
726
xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
727
xmlNsPtr cur;
728
729
if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
730
return(NULL);
731
732
if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
733
/* xml namespace is predefined, no need to add it */
734
if (xmlStrEqual(href, XML_XML_NAMESPACE))
735
return(NULL);
736
737
/*
738
* Problem, this is an attempt to bind xml prefix to a wrong
739
* namespace, which breaks
740
* Namespace constraint: Reserved Prefixes and Namespace Names
741
* from XML namespace. But documents authors may not care in
742
* their context so let's proceed.
743
*/
744
}
745
746
/*
747
* Allocate a new Namespace and fill the fields.
748
*/
749
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
750
if (cur == NULL) {
751
xmlTreeErrMemory("building namespace");
752
return(NULL);
753
}
754
memset(cur, 0, sizeof(xmlNs));
755
cur->type = XML_LOCAL_NAMESPACE;
756
757
if (href != NULL)
758
cur->href = xmlStrdup(href);
759
if (prefix != NULL)
760
cur->prefix = xmlStrdup(prefix);
761
762
/*
763
* Add it at the end to preserve parsing order ...
764
* and checks for existing use of the prefix
765
*/
766
if (node != NULL) {
767
if (node->nsDef == NULL) {
768
node->nsDef = cur;
769
} else {
770
xmlNsPtr prev = node->nsDef;
771
772
if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
773
(xmlStrEqual(prev->prefix, cur->prefix))) {
774
xmlFreeNs(cur);
775
return(NULL);
776
}
777
while (prev->next != NULL) {
778
prev = prev->next;
779
if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
780
(xmlStrEqual(prev->prefix, cur->prefix))) {
781
xmlFreeNs(cur);
782
return(NULL);
783
}
784
}
785
prev->next = cur;
786
}
787
}
788
return(cur);
789
}
790
791
/**
792
* xmlSetNs:
793
* @node: a node in the document
794
* @ns: a namespace pointer
795
*
796
* Associate a namespace to a node, a posteriori.
797
*/
798
void
799
xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
800
if (node == NULL) {
801
return;
802
}
803
if ((node->type == XML_ELEMENT_NODE) ||
804
(node->type == XML_ATTRIBUTE_NODE))
805
node->ns = ns;
806
}
807
808
/**
809
* xmlFreeNs:
810
* @cur: the namespace pointer
811
*
812
* Free up the structures associated to a namespace
813
*/
814
void
815
xmlFreeNs(xmlNsPtr cur) {
816
if (cur == NULL) {
817
return;
818
}
819
if (cur->href != NULL) xmlFree((char *) cur->href);
820
if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
821
xmlFree(cur);
822
}
823
824
/**
825
* xmlFreeNsList:
826
* @cur: the first namespace pointer
827
*
828
* Free up all the structures associated to the chained namespaces.
829
*/
830
void
831
xmlFreeNsList(xmlNsPtr cur) {
832
xmlNsPtr next;
833
if (cur == NULL) {
834
return;
835
}
836
while (cur != NULL) {
837
next = cur->next;
838
xmlFreeNs(cur);
839
cur = next;
840
}
841
}
842
843
/**
844
* xmlNewDtd:
845
* @doc: the document pointer
846
* @name: the DTD name
847
* @ExternalID: the external ID
848
* @SystemID: the system ID
849
*
850
* Creation of a new DTD for the external subset. To create an
851
* internal subset, use xmlCreateIntSubset().
852
*
853
* Returns a pointer to the new DTD structure
854
*/
855
xmlDtdPtr
856
xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
857
const xmlChar *ExternalID, const xmlChar *SystemID) {
858
xmlDtdPtr cur;
859
860
if ((doc != NULL) && (doc->extSubset != NULL)) {
861
return(NULL);
862
}
863
864
/*
865
* Allocate a new DTD and fill the fields.
866
*/
867
cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
868
if (cur == NULL) {
869
xmlTreeErrMemory("building DTD");
870
return(NULL);
871
}
872
memset(cur, 0 , sizeof(xmlDtd));
873
cur->type = XML_DTD_NODE;
874
875
if (name != NULL)
876
cur->name = xmlStrdup(name);
877
if (ExternalID != NULL)
878
cur->ExternalID = xmlStrdup(ExternalID);
879
if (SystemID != NULL)
880
cur->SystemID = xmlStrdup(SystemID);
881
if (doc != NULL)
882
doc->extSubset = cur;
883
cur->doc = doc;
884
885
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
886
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
887
return(cur);
888
}
889
890
/**
891
* xmlGetIntSubset:
892
* @doc: the document pointer
893
*
894
* Get the internal subset of a document
895
* Returns a pointer to the DTD structure or NULL if not found
896
*/
897
898
xmlDtdPtr
899
xmlGetIntSubset(const xmlDoc *doc) {
900
xmlNodePtr cur;
901
902
if (doc == NULL)
903
return(NULL);
904
cur = doc->children;
905
while (cur != NULL) {
906
if (cur->type == XML_DTD_NODE)
907
return((xmlDtdPtr) cur);
908
cur = cur->next;
909
}
910
return((xmlDtdPtr) doc->intSubset);
911
}
912
913
/**
914
* xmlCreateIntSubset:
915
* @doc: the document pointer
916
* @name: the DTD name
917
* @ExternalID: the external (PUBLIC) ID
918
* @SystemID: the system ID
919
*
920
* Create the internal subset of a document
921
* Returns a pointer to the new DTD structure
922
*/
923
xmlDtdPtr
924
xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
925
const xmlChar *ExternalID, const xmlChar *SystemID) {
926
xmlDtdPtr cur;
927
928
if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
929
return(NULL);
930
}
931
932
/*
933
* Allocate a new DTD and fill the fields.
934
*/
935
cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
936
if (cur == NULL) {
937
xmlTreeErrMemory("building internal subset");
938
return(NULL);
939
}
940
memset(cur, 0, sizeof(xmlDtd));
941
cur->type = XML_DTD_NODE;
942
943
if (name != NULL) {
944
cur->name = xmlStrdup(name);
945
if (cur->name == NULL) {
946
xmlTreeErrMemory("building internal subset");
947
xmlFree(cur);
948
return(NULL);
949
}
950
}
951
if (ExternalID != NULL) {
952
cur->ExternalID = xmlStrdup(ExternalID);
953
if (cur->ExternalID == NULL) {
954
xmlTreeErrMemory("building internal subset");
955
if (cur->name != NULL)
956
xmlFree((char *)cur->name);
957
xmlFree(cur);
958
return(NULL);
959
}
960
}
961
if (SystemID != NULL) {
962
cur->SystemID = xmlStrdup(SystemID);
963
if (cur->SystemID == NULL) {
964
xmlTreeErrMemory("building internal subset");
965
if (cur->name != NULL)
966
xmlFree((char *)cur->name);
967
if (cur->ExternalID != NULL)
968
xmlFree((char *)cur->ExternalID);
969
xmlFree(cur);
970
return(NULL);
971
}
972
}
973
if (doc != NULL) {
974
doc->intSubset = cur;
975
cur->parent = doc;
976
cur->doc = doc;
977
if (doc->children == NULL) {
978
doc->children = (xmlNodePtr) cur;
979
doc->last = (xmlNodePtr) cur;
980
} else {
981
if (doc->type == XML_HTML_DOCUMENT_NODE) {
982
xmlNodePtr prev;
983
984
prev = doc->children;
985
prev->prev = (xmlNodePtr) cur;
986
cur->next = prev;
987
doc->children = (xmlNodePtr) cur;
988
} else {
989
xmlNodePtr next;
990
991
next = doc->children;
992
while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
993
next = next->next;
994
if (next == NULL) {
995
cur->prev = doc->last;
996
cur->prev->next = (xmlNodePtr) cur;
997
cur->next = NULL;
998
doc->last = (xmlNodePtr) cur;
999
} else {
1000
cur->next = next;
1001
cur->prev = next->prev;
1002
if (cur->prev == NULL)
1003
doc->children = (xmlNodePtr) cur;
1004
else
1005
cur->prev->next = (xmlNodePtr) cur;
1006
next->prev = (xmlNodePtr) cur;
1007
}
1008
}
1009
}
1010
}
1011
1012
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1013
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1014
return(cur);
1015
}
1016
1017
/**
1018
* DICT_FREE:
1019
* @str: a string
1020
*
1021
* Free a string if it is not owned by the "dict" dictionary in the
1022
* current scope
1023
*/
1024
#define DICT_FREE(str) \
1025
if ((str) && ((!dict) || \
1026
(xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1027
xmlFree((char *)(str));
1028
1029
1030
/**
1031
* DICT_COPY:
1032
* @str: a string
1033
*
1034
* Copy a string using a "dict" dictionary in the current scope,
1035
* if available.
1036
*/
1037
#define DICT_COPY(str, cpy) \
1038
if (str) { \
1039
if (dict) { \
1040
if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1041
cpy = (xmlChar *) (str); \
1042
else \
1043
cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1044
} else \
1045
cpy = xmlStrdup((const xmlChar *)(str)); }
1046
1047
/**
1048
* DICT_CONST_COPY:
1049
* @str: a string
1050
*
1051
* Copy a string using a "dict" dictionary in the current scope,
1052
* if available.
1053
*/
1054
#define DICT_CONST_COPY(str, cpy) \
1055
if (str) { \
1056
if (dict) { \
1057
if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1058
cpy = (const xmlChar *) (str); \
1059
else \
1060
cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1061
} else \
1062
cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1063
1064
1065
/**
1066
* xmlFreeDtd:
1067
* @cur: the DTD structure to free up
1068
*
1069
* Free a DTD structure.
1070
*/
1071
void
1072
xmlFreeDtd(xmlDtdPtr cur) {
1073
xmlDictPtr dict = NULL;
1074
1075
if (cur == NULL) {
1076
return;
1077
}
1078
if (cur->doc != NULL) dict = cur->doc->dict;
1079
1080
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1081
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1082
1083
if (cur->children != NULL) {
1084
xmlNodePtr next, c = cur->children;
1085
1086
/*
1087
* Cleanup all nodes which are not part of the specific lists
1088
* of notations, elements, attributes and entities.
1089
*/
1090
while (c != NULL) {
1091
next = c->next;
1092
if ((c->type != XML_NOTATION_NODE) &&
1093
(c->type != XML_ELEMENT_DECL) &&
1094
(c->type != XML_ATTRIBUTE_DECL) &&
1095
(c->type != XML_ENTITY_DECL)) {
1096
xmlUnlinkNode(c);
1097
xmlFreeNode(c);
1098
}
1099
c = next;
1100
}
1101
}
1102
DICT_FREE(cur->name)
1103
DICT_FREE(cur->SystemID)
1104
DICT_FREE(cur->ExternalID)
1105
/* TODO !!! */
1106
if (cur->notations != NULL)
1107
xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1108
1109
if (cur->elements != NULL)
1110
xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1111
if (cur->attributes != NULL)
1112
xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1113
if (cur->entities != NULL)
1114
xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1115
if (cur->pentities != NULL)
1116
xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1117
1118
xmlFree(cur);
1119
}
1120
1121
/**
1122
* xmlNewDoc:
1123
* @version: xmlChar string giving the version of XML "1.0"
1124
*
1125
* Creates a new XML document
1126
*
1127
* Returns a new document
1128
*/
1129
xmlDocPtr
1130
xmlNewDoc(const xmlChar *version) {
1131
xmlDocPtr cur;
1132
1133
if (version == NULL)
1134
version = (const xmlChar *) "1.0";
1135
1136
/*
1137
* Allocate a new document and fill the fields.
1138
*/
1139
cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1140
if (cur == NULL) {
1141
xmlTreeErrMemory("building doc");
1142
return(NULL);
1143
}
1144
memset(cur, 0, sizeof(xmlDoc));
1145
cur->type = XML_DOCUMENT_NODE;
1146
1147
cur->version = xmlStrdup(version);
1148
if (cur->version == NULL) {
1149
xmlTreeErrMemory("building doc");
1150
xmlFree(cur);
1151
return(NULL);
1152
}
1153
cur->standalone = -1;
1154
cur->compression = -1; /* not initialized */
1155
cur->doc = cur;
1156
cur->parseFlags = 0;
1157
cur->properties = XML_DOC_USERBUILT;
1158
/*
1159
* The in memory encoding is always UTF8
1160
* This field will never change and would
1161
* be obsolete if not for binary compatibility.
1162
*/
1163
cur->charset = XML_CHAR_ENCODING_UTF8;
1164
1165
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1166
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1167
return(cur);
1168
}
1169
1170
/**
1171
* xmlFreeDoc:
1172
* @cur: pointer to the document
1173
*
1174
* Free up all the structures used by a document, tree included.
1175
*/
1176
void
1177
xmlFreeDoc(xmlDocPtr cur) {
1178
xmlDtdPtr extSubset, intSubset;
1179
xmlDictPtr dict = NULL;
1180
1181
if (cur == NULL) {
1182
return;
1183
}
1184
1185
if (cur != NULL) dict = cur->dict;
1186
1187
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1188
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1189
1190
/*
1191
* Do this before freeing the children list to avoid ID lookups
1192
*/
1193
if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1194
cur->ids = NULL;
1195
if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1196
cur->refs = NULL;
1197
extSubset = cur->extSubset;
1198
intSubset = cur->intSubset;
1199
if (intSubset == extSubset)
1200
extSubset = NULL;
1201
if (extSubset != NULL) {
1202
xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1203
cur->extSubset = NULL;
1204
xmlFreeDtd(extSubset);
1205
}
1206
if (intSubset != NULL) {
1207
xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1208
cur->intSubset = NULL;
1209
xmlFreeDtd(intSubset);
1210
}
1211
1212
if (cur->children != NULL) xmlFreeNodeList(cur->children);
1213
if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1214
1215
DICT_FREE(cur->version)
1216
DICT_FREE(cur->name)
1217
DICT_FREE(cur->encoding)
1218
DICT_FREE(cur->URL)
1219
xmlFree(cur);
1220
if (dict) xmlDictFree(dict);
1221
}
1222
1223
/**
1224
* xmlStringLenGetNodeList:
1225
* @doc: the document
1226
* @value: the value of the text
1227
* @len: the length of the string value
1228
*
1229
* Parse the value string and build the node list associated. Should
1230
* produce a flat tree with only TEXTs and ENTITY_REFs.
1231
* Returns a pointer to the first child
1232
*/
1233
xmlNodePtr
1234
xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
1235
xmlNodePtr ret = NULL, last = NULL;
1236
xmlNodePtr node;
1237
xmlChar *val;
1238
const xmlChar *cur, *end;
1239
const xmlChar *q;
1240
xmlEntityPtr ent;
1241
xmlBufPtr buf;
1242
1243
if (value == NULL) return(NULL);
1244
cur = value;
1245
end = cur + len;
1246
1247
buf = xmlBufCreateSize(0);
1248
if (buf == NULL) return(NULL);
1249
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1250
1251
q = cur;
1252
while ((cur < end) && (*cur != 0)) {
1253
if (cur[0] == '&') {
1254
int charval = 0;
1255
xmlChar tmp;
1256
1257
/*
1258
* Save the current text.
1259
*/
1260
if (cur != q) {
1261
if (xmlBufAdd(buf, q, cur - q))
1262
goto out;
1263
}
1264
q = cur;
1265
if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1266
cur += 3;
1267
if (cur < end)
1268
tmp = *cur;
1269
else
1270
tmp = 0;
1271
while (tmp != ';') { /* Non input consuming loop */
1272
/*
1273
* If you find an integer overflow here when fuzzing,
1274
* the bug is probably elsewhere. This function should
1275
* only receive entities that were already validated by
1276
* the parser, typically by xmlParseAttValueComplex
1277
* calling xmlStringDecodeEntities.
1278
*
1279
* So it's better *not* to check for overflow to
1280
* potentially discover new bugs.
1281
*/
1282
if ((tmp >= '0') && (tmp <= '9'))
1283
charval = charval * 16 + (tmp - '0');
1284
else if ((tmp >= 'a') && (tmp <= 'f'))
1285
charval = charval * 16 + (tmp - 'a') + 10;
1286
else if ((tmp >= 'A') && (tmp <= 'F'))
1287
charval = charval * 16 + (tmp - 'A') + 10;
1288
else {
1289
xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1290
NULL);
1291
charval = 0;
1292
break;
1293
}
1294
cur++;
1295
if (cur < end)
1296
tmp = *cur;
1297
else
1298
tmp = 0;
1299
}
1300
if (tmp == ';')
1301
cur++;
1302
q = cur;
1303
} else if ((cur + 1 < end) && (cur[1] == '#')) {
1304
cur += 2;
1305
if (cur < end)
1306
tmp = *cur;
1307
else
1308
tmp = 0;
1309
while (tmp != ';') { /* Non input consuming loops */
1310
/* Don't check for integer overflow, see above. */
1311
if ((tmp >= '0') && (tmp <= '9'))
1312
charval = charval * 10 + (tmp - '0');
1313
else {
1314
xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1315
NULL);
1316
charval = 0;
1317
break;
1318
}
1319
cur++;
1320
if (cur < end)
1321
tmp = *cur;
1322
else
1323
tmp = 0;
1324
}
1325
if (tmp == ';')
1326
cur++;
1327
q = cur;
1328
} else {
1329
/*
1330
* Read the entity string
1331
*/
1332
cur++;
1333
q = cur;
1334
while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1335
if ((cur >= end) || (*cur == 0)) {
1336
xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1337
(const char *) q);
1338
goto out;
1339
}
1340
if (cur != q) {
1341
/*
1342
* Predefined entities don't generate nodes
1343
*/
1344
val = xmlStrndup(q, cur - q);
1345
ent = xmlGetDocEntity(doc, val);
1346
if ((ent != NULL) &&
1347
(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1348
1349
if (xmlBufCat(buf, ent->content))
1350
goto out;
1351
1352
} else {
1353
/*
1354
* Flush buffer so far
1355
*/
1356
if (!xmlBufIsEmpty(buf)) {
1357
node = xmlNewDocText(doc, NULL);
1358
if (node == NULL) {
1359
if (val != NULL) xmlFree(val);
1360
goto out;
1361
}
1362
node->content = xmlBufDetach(buf);
1363
1364
if (last == NULL) {
1365
last = ret = node;
1366
} else {
1367
last = xmlAddNextSibling(last, node);
1368
}
1369
}
1370
1371
/*
1372
* Create a new REFERENCE_REF node
1373
*/
1374
node = xmlNewReference(doc, val);
1375
if (node == NULL) {
1376
if (val != NULL) xmlFree(val);
1377
goto out;
1378
}
1379
else if ((ent != NULL) &&
1380
((ent->flags & XML_ENT_PARSED) == 0) &&
1381
((ent->flags & XML_ENT_EXPANDING) == 0)) {
1382
xmlNodePtr temp;
1383
1384
/*
1385
* The entity should have been checked already,
1386
* but set the flag anyway to avoid recursion.
1387
*/
1388
ent->flags |= XML_ENT_EXPANDING;
1389
ent->children = xmlStringGetNodeList(doc,
1390
(const xmlChar*)node->content);
1391
ent->owner = 1;
1392
ent->flags &= ~XML_ENT_EXPANDING;
1393
ent->flags |= XML_ENT_PARSED;
1394
temp = ent->children;
1395
while (temp) {
1396
temp->parent = (xmlNodePtr)ent;
1397
ent->last = temp;
1398
temp = temp->next;
1399
}
1400
}
1401
if (last == NULL) {
1402
last = ret = node;
1403
} else {
1404
last = xmlAddNextSibling(last, node);
1405
}
1406
}
1407
xmlFree(val);
1408
}
1409
cur++;
1410
q = cur;
1411
}
1412
if (charval != 0) {
1413
xmlChar buffer[10];
1414
int l;
1415
1416
l = xmlCopyCharMultiByte(buffer, charval);
1417
buffer[l] = 0;
1418
1419
if (xmlBufCat(buf, buffer))
1420
goto out;
1421
charval = 0;
1422
}
1423
} else
1424
cur++;
1425
}
1426
1427
if (cur != q) {
1428
/*
1429
* Handle the last piece of text.
1430
*/
1431
if (xmlBufAdd(buf, q, cur - q))
1432
goto out;
1433
}
1434
1435
if (!xmlBufIsEmpty(buf)) {
1436
node = xmlNewDocText(doc, NULL);
1437
if (node == NULL) goto out;
1438
node->content = xmlBufDetach(buf);
1439
1440
if (last == NULL) {
1441
ret = node;
1442
} else {
1443
xmlAddNextSibling(last, node);
1444
}
1445
} else if (ret == NULL) {
1446
ret = xmlNewDocText(doc, BAD_CAST "");
1447
}
1448
1449
out:
1450
xmlBufFree(buf);
1451
return(ret);
1452
}
1453
1454
/**
1455
* xmlStringGetNodeList:
1456
* @doc: the document
1457
* @value: the value of the attribute
1458
*
1459
* Parse the value string and build the node list associated. Should
1460
* produce a flat tree with only TEXTs and ENTITY_REFs.
1461
* Returns a pointer to the first child
1462
*/
1463
xmlNodePtr
1464
xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1465
xmlNodePtr ret = NULL, head = NULL, last = NULL;
1466
xmlNodePtr node;
1467
xmlChar *val = NULL;
1468
const xmlChar *cur = value;
1469
const xmlChar *q;
1470
xmlEntityPtr ent;
1471
xmlBufPtr buf;
1472
1473
if (value == NULL) return(NULL);
1474
1475
buf = xmlBufCreateSize(0);
1476
if (buf == NULL) return(NULL);
1477
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1478
1479
q = cur;
1480
while (*cur != 0) {
1481
if (cur[0] == '&') {
1482
int charval = 0;
1483
xmlChar tmp;
1484
1485
/*
1486
* Save the current text.
1487
*/
1488
if (cur != q) {
1489
if (xmlBufAdd(buf, q, cur - q))
1490
goto out;
1491
}
1492
q = cur;
1493
if ((cur[1] == '#') && (cur[2] == 'x')) {
1494
cur += 3;
1495
tmp = *cur;
1496
while (tmp != ';') { /* Non input consuming loop */
1497
/* Don't check for integer overflow, see above. */
1498
if ((tmp >= '0') && (tmp <= '9'))
1499
charval = charval * 16 + (tmp - '0');
1500
else if ((tmp >= 'a') && (tmp <= 'f'))
1501
charval = charval * 16 + (tmp - 'a') + 10;
1502
else if ((tmp >= 'A') && (tmp <= 'F'))
1503
charval = charval * 16 + (tmp - 'A') + 10;
1504
else {
1505
xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1506
NULL);
1507
charval = 0;
1508
break;
1509
}
1510
cur++;
1511
tmp = *cur;
1512
}
1513
if (tmp == ';')
1514
cur++;
1515
q = cur;
1516
} else if (cur[1] == '#') {
1517
cur += 2;
1518
tmp = *cur;
1519
while (tmp != ';') { /* Non input consuming loops */
1520
/* Don't check for integer overflow, see above. */
1521
if ((tmp >= '0') && (tmp <= '9'))
1522
charval = charval * 10 + (tmp - '0');
1523
else {
1524
xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1525
NULL);
1526
charval = 0;
1527
break;
1528
}
1529
cur++;
1530
tmp = *cur;
1531
}
1532
if (tmp == ';')
1533
cur++;
1534
q = cur;
1535
} else {
1536
/*
1537
* Read the entity string
1538
*/
1539
cur++;
1540
q = cur;
1541
while ((*cur != 0) && (*cur != ';')) cur++;
1542
if (*cur == 0) {
1543
xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1544
(xmlNodePtr) doc, (const char *) q);
1545
goto out;
1546
}
1547
if (cur != q) {
1548
/*
1549
* Predefined entities don't generate nodes
1550
*/
1551
val = xmlStrndup(q, cur - q);
1552
ent = xmlGetDocEntity(doc, val);
1553
if ((ent != NULL) &&
1554
(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1555
1556
if (xmlBufCat(buf, ent->content))
1557
goto out;
1558
1559
} else {
1560
/*
1561
* Flush buffer so far
1562
*/
1563
if (!xmlBufIsEmpty(buf)) {
1564
node = xmlNewDocText(doc, NULL);
1565
if (node == NULL)
1566
goto out;
1567
node->content = xmlBufDetach(buf);
1568
1569
if (last == NULL) {
1570
last = head = node;
1571
} else {
1572
last = xmlAddNextSibling(last, node);
1573
}
1574
}
1575
1576
/*
1577
* Create a new REFERENCE_REF node
1578
*/
1579
node = xmlNewReference(doc, val);
1580
if (node == NULL)
1581
goto out;
1582
if ((ent != NULL) &&
1583
((ent->flags & XML_ENT_PARSED) == 0) &&
1584
((ent->flags & XML_ENT_EXPANDING) == 0)) {
1585
xmlNodePtr temp;
1586
1587
/*
1588
* The entity should have been checked already,
1589
* but set the flag anyway to avoid recursion.
1590
*/
1591
ent->flags |= XML_ENT_EXPANDING;
1592
ent->children = xmlStringGetNodeList(doc,
1593
(const xmlChar*)node->content);
1594
ent->owner = 1;
1595
ent->flags &= ~XML_ENT_EXPANDING;
1596
ent->flags |= XML_ENT_PARSED;
1597
temp = ent->children;
1598
while (temp) {
1599
temp->parent = (xmlNodePtr)ent;
1600
ent->last = temp;
1601
temp = temp->next;
1602
}
1603
}
1604
if (last == NULL) {
1605
last = head = node;
1606
} else {
1607
last = xmlAddNextSibling(last, node);
1608
}
1609
}
1610
xmlFree(val);
1611
val = NULL;
1612
}
1613
cur++;
1614
q = cur;
1615
}
1616
if (charval != 0) {
1617
xmlChar buffer[10];
1618
int len;
1619
1620
len = xmlCopyCharMultiByte(buffer, charval);
1621
buffer[len] = 0;
1622
1623
if (xmlBufCat(buf, buffer))
1624
goto out;
1625
charval = 0;
1626
}
1627
} else
1628
cur++;
1629
}
1630
if ((cur != q) || (head == NULL)) {
1631
/*
1632
* Handle the last piece of text.
1633
*/
1634
xmlBufAdd(buf, q, cur - q);
1635
}
1636
1637
if (!xmlBufIsEmpty(buf)) {
1638
node = xmlNewDocText(doc, NULL);
1639
if (node == NULL)
1640
goto out;
1641
node->content = xmlBufDetach(buf);
1642
1643
if (last == NULL) {
1644
head = node;
1645
} else {
1646
xmlAddNextSibling(last, node);
1647
}
1648
}
1649
1650
ret = head;
1651
head = NULL;
1652
1653
out:
1654
xmlBufFree(buf);
1655
if (val != NULL) xmlFree(val);
1656
if (head != NULL) xmlFreeNodeList(head);
1657
return(ret);
1658
}
1659
1660
/**
1661
* xmlNodeListGetString:
1662
* @doc: the document
1663
* @list: a Node list
1664
* @inLine: should we replace entity contents or show their external form
1665
*
1666
* Build the string equivalent to the text contained in the Node list
1667
* made of TEXTs and ENTITY_REFs
1668
*
1669
* Returns a pointer to the string copy, the caller must free it with xmlFree().
1670
*/
1671
xmlChar *
1672
xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1673
{
1674
const xmlNode *node = list;
1675
xmlChar *ret = NULL;
1676
xmlEntityPtr ent;
1677
int attr;
1678
1679
if (list == NULL)
1680
return (NULL);
1681
if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1682
attr = 1;
1683
else
1684
attr = 0;
1685
1686
while (node != NULL) {
1687
if ((node->type == XML_TEXT_NODE) ||
1688
(node->type == XML_CDATA_SECTION_NODE)) {
1689
if (inLine) {
1690
ret = xmlStrcat(ret, node->content);
1691
} else {
1692
xmlChar *buffer;
1693
1694
if (attr)
1695
buffer = xmlEncodeAttributeEntities(doc, node->content);
1696
else
1697
buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1698
if (buffer != NULL) {
1699
ret = xmlStrcat(ret, buffer);
1700
xmlFree(buffer);
1701
}
1702
}
1703
} else if (node->type == XML_ENTITY_REF_NODE) {
1704
if (inLine) {
1705
ent = xmlGetDocEntity(doc, node->name);
1706
if (ent != NULL) {
1707
xmlChar *buffer;
1708
1709
/* an entity content can be any "well balanced chunk",
1710
* i.e. the result of the content [43] production:
1711
* http://www.w3.org/TR/REC-xml#NT-content.
1712
* So it can contain text, CDATA section or nested
1713
* entity reference nodes (among others).
1714
* -> we recursive call xmlNodeListGetString()
1715
* which handles these types */
1716
buffer = xmlNodeListGetString(doc, ent->children, 1);
1717
if (buffer != NULL) {
1718
ret = xmlStrcat(ret, buffer);
1719
xmlFree(buffer);
1720
}
1721
} else {
1722
ret = xmlStrcat(ret, node->content);
1723
}
1724
} else {
1725
xmlChar buf[2];
1726
1727
buf[0] = '&';
1728
buf[1] = 0;
1729
ret = xmlStrncat(ret, buf, 1);
1730
ret = xmlStrcat(ret, node->name);
1731
buf[0] = ';';
1732
buf[1] = 0;
1733
ret = xmlStrncat(ret, buf, 1);
1734
}
1735
}
1736
#if 0
1737
else {
1738
xmlGenericError(xmlGenericErrorContext,
1739
"xmlGetNodeListString : invalid node type %d\n",
1740
node->type);
1741
}
1742
#endif
1743
node = node->next;
1744
}
1745
return (ret);
1746
}
1747
1748
#ifdef LIBXML_TREE_ENABLED
1749
/**
1750
* xmlNodeListGetRawString:
1751
* @doc: the document
1752
* @list: a Node list
1753
* @inLine: should we replace entity contents or show their external form
1754
*
1755
* Builds the string equivalent to the text contained in the Node list
1756
* made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1757
* this function doesn't do any character encoding handling.
1758
*
1759
* Returns a pointer to the string copy, the caller must free it with xmlFree().
1760
*/
1761
xmlChar *
1762
xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1763
{
1764
const xmlNode *node = list;
1765
xmlChar *ret = NULL;
1766
xmlEntityPtr ent;
1767
1768
if (list == NULL)
1769
return (NULL);
1770
1771
while (node != NULL) {
1772
if ((node->type == XML_TEXT_NODE) ||
1773
(node->type == XML_CDATA_SECTION_NODE)) {
1774
if (inLine) {
1775
ret = xmlStrcat(ret, node->content);
1776
} else {
1777
xmlChar *buffer;
1778
1779
buffer = xmlEncodeSpecialChars(doc, node->content);
1780
if (buffer != NULL) {
1781
ret = xmlStrcat(ret, buffer);
1782
xmlFree(buffer);
1783
}
1784
}
1785
} else if (node->type == XML_ENTITY_REF_NODE) {
1786
if (inLine) {
1787
ent = xmlGetDocEntity(doc, node->name);
1788
if (ent != NULL) {
1789
xmlChar *buffer;
1790
1791
/* an entity content can be any "well balanced chunk",
1792
* i.e. the result of the content [43] production:
1793
* http://www.w3.org/TR/REC-xml#NT-content.
1794
* So it can contain text, CDATA section or nested
1795
* entity reference nodes (among others).
1796
* -> we recursive call xmlNodeListGetRawString()
1797
* which handles these types */
1798
buffer =
1799
xmlNodeListGetRawString(doc, ent->children, 1);
1800
if (buffer != NULL) {
1801
ret = xmlStrcat(ret, buffer);
1802
xmlFree(buffer);
1803
}
1804
} else {
1805
ret = xmlStrcat(ret, node->content);
1806
}
1807
} else {
1808
xmlChar buf[2];
1809
1810
buf[0] = '&';
1811
buf[1] = 0;
1812
ret = xmlStrncat(ret, buf, 1);
1813
ret = xmlStrcat(ret, node->name);
1814
buf[0] = ';';
1815
buf[1] = 0;
1816
ret = xmlStrncat(ret, buf, 1);
1817
}
1818
}
1819
#if 0
1820
else {
1821
xmlGenericError(xmlGenericErrorContext,
1822
"xmlGetNodeListString : invalid node type %d\n",
1823
node->type);
1824
}
1825
#endif
1826
node = node->next;
1827
}
1828
return (ret);
1829
}
1830
#endif /* LIBXML_TREE_ENABLED */
1831
1832
static xmlAttrPtr
1833
xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1834
const xmlChar * name, const xmlChar * value,
1835
int eatname)
1836
{
1837
xmlAttrPtr cur;
1838
xmlDocPtr doc = NULL;
1839
1840
if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1841
if ((eatname == 1) &&
1842
((node->doc == NULL) || (node->doc->dict == NULL) ||
1843
(!(xmlDictOwns(node->doc->dict, name)))))
1844
xmlFree((xmlChar *) name);
1845
return (NULL);
1846
}
1847
1848
/*
1849
* Allocate a new property and fill the fields.
1850
*/
1851
cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1852
if (cur == NULL) {
1853
if ((eatname == 1) &&
1854
((node == NULL) || (node->doc == NULL) ||
1855
(node->doc->dict == NULL) ||
1856
(!(xmlDictOwns(node->doc->dict, name)))))
1857
xmlFree((xmlChar *) name);
1858
xmlTreeErrMemory("building attribute");
1859
return (NULL);
1860
}
1861
memset(cur, 0, sizeof(xmlAttr));
1862
cur->type = XML_ATTRIBUTE_NODE;
1863
1864
cur->parent = node;
1865
if (node != NULL) {
1866
doc = node->doc;
1867
cur->doc = doc;
1868
}
1869
cur->ns = ns;
1870
1871
if (eatname == 0) {
1872
if ((doc != NULL) && (doc->dict != NULL))
1873
cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1874
else
1875
cur->name = xmlStrdup(name);
1876
} else
1877
cur->name = name;
1878
1879
if (value != NULL) {
1880
xmlNodePtr tmp;
1881
1882
cur->children = xmlNewDocText(doc, value);
1883
cur->last = NULL;
1884
tmp = cur->children;
1885
while (tmp != NULL) {
1886
tmp->parent = (xmlNodePtr) cur;
1887
if (tmp->next == NULL)
1888
cur->last = tmp;
1889
tmp = tmp->next;
1890
}
1891
}
1892
1893
/*
1894
* Add it at the end to preserve parsing order ...
1895
*/
1896
if (node != NULL) {
1897
if (node->properties == NULL) {
1898
node->properties = cur;
1899
} else {
1900
xmlAttrPtr prev = node->properties;
1901
1902
while (prev->next != NULL)
1903
prev = prev->next;
1904
prev->next = cur;
1905
cur->prev = prev;
1906
}
1907
}
1908
1909
if ((value != NULL) && (node != NULL) &&
1910
(xmlIsID(node->doc, node, cur) == 1))
1911
xmlAddID(NULL, node->doc, value, cur);
1912
1913
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1914
xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1915
return (cur);
1916
}
1917
1918
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1919
defined(LIBXML_SCHEMAS_ENABLED)
1920
/**
1921
* xmlNewProp:
1922
* @node: the holding node
1923
* @name: the name of the attribute
1924
* @value: the value of the attribute
1925
*
1926
* Create a new property carried by a node.
1927
* Returns a pointer to the attribute
1928
*/
1929
xmlAttrPtr
1930
xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1931
1932
if (name == NULL) {
1933
return(NULL);
1934
}
1935
1936
return xmlNewPropInternal(node, NULL, name, value, 0);
1937
}
1938
#endif /* LIBXML_TREE_ENABLED */
1939
1940
/**
1941
* xmlNewNsProp:
1942
* @node: the holding node
1943
* @ns: the namespace
1944
* @name: the name of the attribute
1945
* @value: the value of the attribute
1946
*
1947
* Create a new property tagged with a namespace and carried by a node.
1948
* Returns a pointer to the attribute
1949
*/
1950
xmlAttrPtr
1951
xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1952
const xmlChar *value) {
1953
1954
if (name == NULL) {
1955
return(NULL);
1956
}
1957
1958
return xmlNewPropInternal(node, ns, name, value, 0);
1959
}
1960
1961
/**
1962
* xmlNewNsPropEatName:
1963
* @node: the holding node
1964
* @ns: the namespace
1965
* @name: the name of the attribute
1966
* @value: the value of the attribute
1967
*
1968
* Create a new property tagged with a namespace and carried by a node.
1969
* Returns a pointer to the attribute
1970
*/
1971
xmlAttrPtr
1972
xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1973
const xmlChar *value) {
1974
1975
if (name == NULL) {
1976
return(NULL);
1977
}
1978
1979
return xmlNewPropInternal(node, ns, name, value, 1);
1980
}
1981
1982
/**
1983
* xmlNewDocProp:
1984
* @doc: the document
1985
* @name: the name of the attribute
1986
* @value: the value of the attribute
1987
*
1988
* Create a new property carried by a document.
1989
* NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity
1990
* references, but XML special chars need to be escaped first by using
1991
* xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need
1992
* entities support.
1993
*
1994
* Returns a pointer to the attribute
1995
*/
1996
xmlAttrPtr
1997
xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1998
xmlAttrPtr cur;
1999
2000
if (name == NULL) {
2001
return(NULL);
2002
}
2003
2004
/*
2005
* Allocate a new property and fill the fields.
2006
*/
2007
cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2008
if (cur == NULL) {
2009
xmlTreeErrMemory("building attribute");
2010
return(NULL);
2011
}
2012
memset(cur, 0, sizeof(xmlAttr));
2013
cur->type = XML_ATTRIBUTE_NODE;
2014
2015
if ((doc != NULL) && (doc->dict != NULL))
2016
cur->name = xmlDictLookup(doc->dict, name, -1);
2017
else
2018
cur->name = xmlStrdup(name);
2019
cur->doc = doc;
2020
if (value != NULL) {
2021
xmlNodePtr tmp;
2022
2023
cur->children = xmlStringGetNodeList(doc, value);
2024
cur->last = NULL;
2025
2026
tmp = cur->children;
2027
while (tmp != NULL) {
2028
tmp->parent = (xmlNodePtr) cur;
2029
if (tmp->next == NULL)
2030
cur->last = tmp;
2031
tmp = tmp->next;
2032
}
2033
}
2034
2035
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2036
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2037
return(cur);
2038
}
2039
2040
/**
2041
* xmlFreePropList:
2042
* @cur: the first property in the list
2043
*
2044
* Free a property and all its siblings, all the children are freed too.
2045
*/
2046
void
2047
xmlFreePropList(xmlAttrPtr cur) {
2048
xmlAttrPtr next;
2049
if (cur == NULL) return;
2050
while (cur != NULL) {
2051
next = cur->next;
2052
xmlFreeProp(cur);
2053
cur = next;
2054
}
2055
}
2056
2057
/**
2058
* xmlFreeProp:
2059
* @cur: an attribute
2060
*
2061
* Free one attribute, all the content is freed too
2062
*/
2063
void
2064
xmlFreeProp(xmlAttrPtr cur) {
2065
xmlDictPtr dict = NULL;
2066
if (cur == NULL) return;
2067
2068
if (cur->doc != NULL) dict = cur->doc->dict;
2069
2070
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
2071
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2072
2073
/* Check for ID removal -> leading to invalid references ! */
2074
if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2075
xmlRemoveID(cur->doc, cur);
2076
}
2077
if (cur->children != NULL) xmlFreeNodeList(cur->children);
2078
DICT_FREE(cur->name)
2079
xmlFree(cur);
2080
}
2081
2082
/**
2083
* xmlRemoveProp:
2084
* @cur: an attribute
2085
*
2086
* Unlink and free one attribute, all the content is freed too
2087
* Note this doesn't work for namespace definition attributes
2088
*
2089
* Returns 0 if success and -1 in case of error.
2090
*/
2091
int
2092
xmlRemoveProp(xmlAttrPtr cur) {
2093
xmlAttrPtr tmp;
2094
if (cur == NULL) {
2095
return(-1);
2096
}
2097
if (cur->parent == NULL) {
2098
return(-1);
2099
}
2100
tmp = cur->parent->properties;
2101
if (tmp == cur) {
2102
cur->parent->properties = cur->next;
2103
if (cur->next != NULL)
2104
cur->next->prev = NULL;
2105
xmlFreeProp(cur);
2106
return(0);
2107
}
2108
while (tmp != NULL) {
2109
if (tmp->next == cur) {
2110
tmp->next = cur->next;
2111
if (tmp->next != NULL)
2112
tmp->next->prev = tmp;
2113
xmlFreeProp(cur);
2114
return(0);
2115
}
2116
tmp = tmp->next;
2117
}
2118
return(-1);
2119
}
2120
2121
/**
2122
* xmlNewDocPI:
2123
* @doc: the target document
2124
* @name: the processing instruction name
2125
* @content: the PI content
2126
*
2127
* Creation of a processing instruction element.
2128
* Returns a pointer to the new node object.
2129
*/
2130
xmlNodePtr
2131
xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2132
xmlNodePtr cur;
2133
2134
if (name == NULL) {
2135
return(NULL);
2136
}
2137
2138
/*
2139
* Allocate a new node and fill the fields.
2140
*/
2141
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2142
if (cur == NULL) {
2143
xmlTreeErrMemory("building PI");
2144
return(NULL);
2145
}
2146
memset(cur, 0, sizeof(xmlNode));
2147
cur->type = XML_PI_NODE;
2148
2149
if ((doc != NULL) && (doc->dict != NULL))
2150
cur->name = xmlDictLookup(doc->dict, name, -1);
2151
else
2152
cur->name = xmlStrdup(name);
2153
if (content != NULL) {
2154
cur->content = xmlStrdup(content);
2155
}
2156
cur->doc = doc;
2157
2158
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2159
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2160
return(cur);
2161
}
2162
2163
/**
2164
* xmlNewPI:
2165
* @name: the processing instruction name
2166
* @content: the PI content
2167
*
2168
* Creation of a processing instruction element.
2169
*
2170
* Use of this function is DISCOURAGED in favor of xmlNewDocPI.
2171
*
2172
* Returns a pointer to the new node object.
2173
*/
2174
xmlNodePtr
2175
xmlNewPI(const xmlChar *name, const xmlChar *content) {
2176
return(xmlNewDocPI(NULL, name, content));
2177
}
2178
2179
/**
2180
* xmlNewNode:
2181
* @ns: namespace if any
2182
* @name: the node name
2183
*
2184
* Creation of a new node element. @ns is optional (NULL).
2185
*
2186
* Use of this function is DISCOURAGED in favor of xmlNewDocNode.
2187
*
2188
* Returns a pointer to the new node object. Uses xmlStrdup() to make
2189
* copy of @name.
2190
*/
2191
xmlNodePtr
2192
xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2193
xmlNodePtr cur;
2194
2195
if (name == NULL) {
2196
return(NULL);
2197
}
2198
2199
/*
2200
* Allocate a new node and fill the fields.
2201
*/
2202
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2203
if (cur == NULL) {
2204
xmlTreeErrMemory("building node");
2205
return(NULL);
2206
}
2207
memset(cur, 0, sizeof(xmlNode));
2208
cur->type = XML_ELEMENT_NODE;
2209
2210
cur->name = xmlStrdup(name);
2211
cur->ns = ns;
2212
2213
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2214
xmlRegisterNodeDefaultValue(cur);
2215
return(cur);
2216
}
2217
2218
/**
2219
* xmlNewNodeEatName:
2220
* @ns: namespace if any
2221
* @name: the node name
2222
*
2223
* Creation of a new node element. @ns is optional (NULL).
2224
*
2225
* Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName.
2226
*
2227
* Returns a pointer to the new node object, with pointer @name as
2228
* new node's name. Use xmlNewNode() if a copy of @name string is
2229
* is needed as new node's name.
2230
*/
2231
xmlNodePtr
2232
xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2233
xmlNodePtr cur;
2234
2235
if (name == NULL) {
2236
return(NULL);
2237
}
2238
2239
/*
2240
* Allocate a new node and fill the fields.
2241
*/
2242
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2243
if (cur == NULL) {
2244
xmlTreeErrMemory("building node");
2245
/* we can't check here that name comes from the doc dictionary */
2246
return(NULL);
2247
}
2248
memset(cur, 0, sizeof(xmlNode));
2249
cur->type = XML_ELEMENT_NODE;
2250
2251
cur->name = name;
2252
cur->ns = ns;
2253
2254
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2255
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2256
return(cur);
2257
}
2258
2259
/**
2260
* xmlNewDocNode:
2261
* @doc: the document
2262
* @ns: namespace if any
2263
* @name: the node name
2264
* @content: the XML text content if any
2265
*
2266
* Creation of a new node element within a document. @ns and @content
2267
* are optional (NULL).
2268
* NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2269
* references, but XML special chars need to be escaped first by using
2270
* xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2271
* need entities support.
2272
*
2273
* Returns a pointer to the new node object.
2274
*/
2275
xmlNodePtr
2276
xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2277
const xmlChar *name, const xmlChar *content) {
2278
xmlNodePtr cur;
2279
2280
if ((doc != NULL) && (doc->dict != NULL))
2281
cur = xmlNewNodeEatName(ns, (xmlChar *)
2282
xmlDictLookup(doc->dict, name, -1));
2283
else
2284
cur = xmlNewNode(ns, name);
2285
if (cur != NULL) {
2286
cur->doc = doc;
2287
if (content != NULL) {
2288
cur->children = xmlStringGetNodeList(doc, content);
2289
UPDATE_LAST_CHILD_AND_PARENT(cur)
2290
}
2291
}
2292
2293
return(cur);
2294
}
2295
2296
/**
2297
* xmlNewDocNodeEatName:
2298
* @doc: the document
2299
* @ns: namespace if any
2300
* @name: the node name
2301
* @content: the XML text content if any
2302
*
2303
* Creation of a new node element within a document. @ns and @content
2304
* are optional (NULL).
2305
* NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2306
* references, but XML special chars need to be escaped first by using
2307
* xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2308
* need entities support.
2309
*
2310
* Returns a pointer to the new node object.
2311
*/
2312
xmlNodePtr
2313
xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2314
xmlChar *name, const xmlChar *content) {
2315
xmlNodePtr cur;
2316
2317
cur = xmlNewNodeEatName(ns, name);
2318
if (cur != NULL) {
2319
cur->doc = doc;
2320
if (content != NULL) {
2321
cur->children = xmlStringGetNodeList(doc, content);
2322
UPDATE_LAST_CHILD_AND_PARENT(cur)
2323
}
2324
} else {
2325
/* if name don't come from the doc dictionary free it here */
2326
if ((name != NULL) &&
2327
((doc == NULL) || (doc->dict == NULL) ||
2328
(!(xmlDictOwns(doc->dict, name)))))
2329
xmlFree(name);
2330
}
2331
return(cur);
2332
}
2333
2334
#ifdef LIBXML_TREE_ENABLED
2335
/**
2336
* xmlNewDocRawNode:
2337
* @doc: the document
2338
* @ns: namespace if any
2339
* @name: the node name
2340
* @content: the text content if any
2341
*
2342
* Creation of a new node element within a document. @ns and @content
2343
* are optional (NULL).
2344
*
2345
* Returns a pointer to the new node object.
2346
*/
2347
xmlNodePtr
2348
xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2349
const xmlChar *name, const xmlChar *content) {
2350
xmlNodePtr cur;
2351
2352
cur = xmlNewDocNode(doc, ns, name, NULL);
2353
if (cur != NULL) {
2354
cur->doc = doc;
2355
if (content != NULL) {
2356
cur->children = xmlNewDocText(doc, content);
2357
UPDATE_LAST_CHILD_AND_PARENT(cur)
2358
}
2359
}
2360
return(cur);
2361
}
2362
2363
/**
2364
* xmlNewDocFragment:
2365
* @doc: the document owning the fragment
2366
*
2367
* Creation of a new Fragment node.
2368
* Returns a pointer to the new node object.
2369
*/
2370
xmlNodePtr
2371
xmlNewDocFragment(xmlDocPtr doc) {
2372
xmlNodePtr cur;
2373
2374
/*
2375
* Allocate a new DocumentFragment node and fill the fields.
2376
*/
2377
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2378
if (cur == NULL) {
2379
xmlTreeErrMemory("building fragment");
2380
return(NULL);
2381
}
2382
memset(cur, 0, sizeof(xmlNode));
2383
cur->type = XML_DOCUMENT_FRAG_NODE;
2384
2385
cur->doc = doc;
2386
2387
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2388
xmlRegisterNodeDefaultValue(cur);
2389
return(cur);
2390
}
2391
#endif /* LIBXML_TREE_ENABLED */
2392
2393
/**
2394
* xmlNewText:
2395
* @content: the text content
2396
*
2397
* Creation of a new text node.
2398
*
2399
* Use of this function is DISCOURAGED in favor of xmlNewDocText.
2400
*
2401
* Returns a pointer to the new node object.
2402
*/
2403
xmlNodePtr
2404
xmlNewText(const xmlChar *content) {
2405
xmlNodePtr cur;
2406
2407
/*
2408
* Allocate a new node and fill the fields.
2409
*/
2410
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2411
if (cur == NULL) {
2412
xmlTreeErrMemory("building text");
2413
return(NULL);
2414
}
2415
memset(cur, 0, sizeof(xmlNode));
2416
cur->type = XML_TEXT_NODE;
2417
2418
cur->name = xmlStringText;
2419
if (content != NULL) {
2420
cur->content = xmlStrdup(content);
2421
}
2422
2423
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2424
xmlRegisterNodeDefaultValue(cur);
2425
return(cur);
2426
}
2427
2428
#ifdef LIBXML_TREE_ENABLED
2429
/**
2430
* xmlNewTextChild:
2431
* @parent: the parent node
2432
* @ns: a namespace if any
2433
* @name: the name of the child
2434
* @content: the text content of the child if any.
2435
*
2436
* Creation of a new child element, added at the end of @parent children list.
2437
* @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2438
* created element inherits the namespace of @parent. If @content is non NULL,
2439
* a child TEXT node will be created containing the string @content.
2440
* NOTE: Use xmlNewChild() if @content will contain entities that need to be
2441
* preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2442
* reserved XML chars that might appear in @content, such as the ampersand,
2443
* greater-than or less-than signs, are automatically replaced by their XML
2444
* escaped entity representations.
2445
*
2446
* Returns a pointer to the new node object.
2447
*/
2448
xmlNodePtr
2449
xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2450
const xmlChar *name, const xmlChar *content) {
2451
xmlNodePtr cur, prev;
2452
2453
if (parent == NULL) {
2454
return(NULL);
2455
}
2456
2457
if (name == NULL) {
2458
return(NULL);
2459
}
2460
2461
/*
2462
* Allocate a new node
2463
*/
2464
if (parent->type == XML_ELEMENT_NODE) {
2465
if (ns == NULL)
2466
cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2467
else
2468
cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2469
} else if ((parent->type == XML_DOCUMENT_NODE) ||
2470
(parent->type == XML_HTML_DOCUMENT_NODE)) {
2471
if (ns == NULL)
2472
cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2473
else
2474
cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2475
} else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2476
cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2477
} else {
2478
return(NULL);
2479
}
2480
if (cur == NULL) return(NULL);
2481
2482
/*
2483
* add the new element at the end of the children list.
2484
*/
2485
cur->type = XML_ELEMENT_NODE;
2486
cur->parent = parent;
2487
cur->doc = parent->doc;
2488
if (parent->children == NULL) {
2489
parent->children = cur;
2490
parent->last = cur;
2491
} else {
2492
prev = parent->last;
2493
prev->next = cur;
2494
cur->prev = prev;
2495
parent->last = cur;
2496
}
2497
2498
return(cur);
2499
}
2500
#endif /* LIBXML_TREE_ENABLED */
2501
2502
/**
2503
* xmlNewCharRef:
2504
* @doc: the document
2505
* @name: the char ref string, starting with # or "&# ... ;"
2506
*
2507
* Creation of a new character reference node.
2508
* Returns a pointer to the new node object.
2509
*/
2510
xmlNodePtr
2511
xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2512
xmlNodePtr cur;
2513
2514
if (name == NULL)
2515
return(NULL);
2516
2517
/*
2518
* Allocate a new node and fill the fields.
2519
*/
2520
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2521
if (cur == NULL) {
2522
xmlTreeErrMemory("building character reference");
2523
return(NULL);
2524
}
2525
memset(cur, 0, sizeof(xmlNode));
2526
cur->type = XML_ENTITY_REF_NODE;
2527
2528
cur->doc = doc;
2529
if (name[0] == '&') {
2530
int len;
2531
name++;
2532
len = xmlStrlen(name);
2533
if (name[len - 1] == ';')
2534
cur->name = xmlStrndup(name, len - 1);
2535
else
2536
cur->name = xmlStrndup(name, len);
2537
} else
2538
cur->name = xmlStrdup(name);
2539
2540
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2541
xmlRegisterNodeDefaultValue(cur);
2542
return(cur);
2543
}
2544
2545
/**
2546
* xmlNewReference:
2547
* @doc: the document
2548
* @name: the reference name, or the reference string with & and ;
2549
*
2550
* Creation of a new reference node.
2551
* Returns a pointer to the new node object.
2552
*/
2553
xmlNodePtr
2554
xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2555
xmlNodePtr cur;
2556
xmlEntityPtr ent;
2557
2558
if (name == NULL)
2559
return(NULL);
2560
2561
/*
2562
* Allocate a new node and fill the fields.
2563
*/
2564
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2565
if (cur == NULL) {
2566
xmlTreeErrMemory("building reference");
2567
return(NULL);
2568
}
2569
memset(cur, 0, sizeof(xmlNode));
2570
cur->type = XML_ENTITY_REF_NODE;
2571
2572
cur->doc = (xmlDoc *)doc;
2573
if (name[0] == '&') {
2574
int len;
2575
name++;
2576
len = xmlStrlen(name);
2577
if (name[len - 1] == ';')
2578
cur->name = xmlStrndup(name, len - 1);
2579
else
2580
cur->name = xmlStrndup(name, len);
2581
} else
2582
cur->name = xmlStrdup(name);
2583
2584
ent = xmlGetDocEntity(doc, cur->name);
2585
if (ent != NULL) {
2586
cur->content = ent->content;
2587
/*
2588
* The parent pointer in entity is a DTD pointer and thus is NOT
2589
* updated. Not sure if this is 100% correct.
2590
* -George
2591
*/
2592
cur->children = (xmlNodePtr) ent;
2593
cur->last = (xmlNodePtr) ent;
2594
}
2595
2596
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2597
xmlRegisterNodeDefaultValue(cur);
2598
return(cur);
2599
}
2600
2601
/**
2602
* xmlNewDocText:
2603
* @doc: the document
2604
* @content: the text content
2605
*
2606
* Creation of a new text node within a document.
2607
* Returns a pointer to the new node object.
2608
*/
2609
xmlNodePtr
2610
xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2611
xmlNodePtr cur;
2612
2613
cur = xmlNewText(content);
2614
if (cur != NULL) cur->doc = (xmlDoc *)doc;
2615
return(cur);
2616
}
2617
2618
/**
2619
* xmlNewTextLen:
2620
* @content: the text content
2621
* @len: the text len.
2622
*
2623
* Use of this function is DISCOURAGED in favor of xmlNewDocTextLen.
2624
*
2625
* Creation of a new text node with an extra parameter for the content's length
2626
* Returns a pointer to the new node object.
2627
*/
2628
xmlNodePtr
2629
xmlNewTextLen(const xmlChar *content, int len) {
2630
xmlNodePtr cur;
2631
2632
/*
2633
* Allocate a new node and fill the fields.
2634
*/
2635
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2636
if (cur == NULL) {
2637
xmlTreeErrMemory("building text");
2638
return(NULL);
2639
}
2640
memset(cur, 0, sizeof(xmlNode));
2641
cur->type = XML_TEXT_NODE;
2642
2643
cur->name = xmlStringText;
2644
if (content != NULL) {
2645
cur->content = xmlStrndup(content, len);
2646
}
2647
2648
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2649
xmlRegisterNodeDefaultValue(cur);
2650
return(cur);
2651
}
2652
2653
/**
2654
* xmlNewDocTextLen:
2655
* @doc: the document
2656
* @content: the text content
2657
* @len: the text len.
2658
*
2659
* Creation of a new text node with an extra content length parameter. The
2660
* text node pertain to a given document.
2661
* Returns a pointer to the new node object.
2662
*/
2663
xmlNodePtr
2664
xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2665
xmlNodePtr cur;
2666
2667
cur = xmlNewTextLen(content, len);
2668
if (cur != NULL) cur->doc = doc;
2669
return(cur);
2670
}
2671
2672
/**
2673
* xmlNewComment:
2674
* @content: the comment content
2675
*
2676
* Use of this function is DISCOURAGED in favor of xmlNewDocComment.
2677
*
2678
* Creation of a new node containing a comment.
2679
* Returns a pointer to the new node object.
2680
*/
2681
xmlNodePtr
2682
xmlNewComment(const xmlChar *content) {
2683
xmlNodePtr cur;
2684
2685
/*
2686
* Allocate a new node and fill the fields.
2687
*/
2688
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2689
if (cur == NULL) {
2690
xmlTreeErrMemory("building comment");
2691
return(NULL);
2692
}
2693
memset(cur, 0, sizeof(xmlNode));
2694
cur->type = XML_COMMENT_NODE;
2695
2696
cur->name = xmlStringComment;
2697
if (content != NULL) {
2698
cur->content = xmlStrdup(content);
2699
}
2700
2701
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2702
xmlRegisterNodeDefaultValue(cur);
2703
return(cur);
2704
}
2705
2706
/**
2707
* xmlNewCDataBlock:
2708
* @doc: the document
2709
* @content: the CDATA block content content
2710
* @len: the length of the block
2711
*
2712
* Creation of a new node containing a CDATA block.
2713
* Returns a pointer to the new node object.
2714
*/
2715
xmlNodePtr
2716
xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2717
xmlNodePtr cur;
2718
2719
/*
2720
* Allocate a new node and fill the fields.
2721
*/
2722
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2723
if (cur == NULL) {
2724
xmlTreeErrMemory("building CDATA");
2725
return(NULL);
2726
}
2727
memset(cur, 0, sizeof(xmlNode));
2728
cur->type = XML_CDATA_SECTION_NODE;
2729
cur->doc = doc;
2730
2731
if (content != NULL) {
2732
cur->content = xmlStrndup(content, len);
2733
}
2734
2735
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2736
xmlRegisterNodeDefaultValue(cur);
2737
return(cur);
2738
}
2739
2740
/**
2741
* xmlNewDocComment:
2742
* @doc: the document
2743
* @content: the comment content
2744
*
2745
* Creation of a new node containing a comment within a document.
2746
* Returns a pointer to the new node object.
2747
*/
2748
xmlNodePtr
2749
xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2750
xmlNodePtr cur;
2751
2752
cur = xmlNewComment(content);
2753
if (cur != NULL) cur->doc = doc;
2754
return(cur);
2755
}
2756
2757
static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
2758
const xmlChar *newValue = oldValue;
2759
if (oldValue) {
2760
int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
2761
if (oldDictOwnsOldValue) {
2762
if (newDict)
2763
newValue = xmlDictLookup(newDict, oldValue, -1);
2764
else
2765
newValue = xmlStrdup(oldValue);
2766
}
2767
}
2768
return newValue;
2769
}
2770
2771
/**
2772
* xmlSetTreeDoc:
2773
* @tree: the top element
2774
* @doc: the document
2775
*
2776
* update all nodes under the tree to point to the right document
2777
*/
2778
void
2779
xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
2780
xmlAttrPtr prop;
2781
2782
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2783
return;
2784
if (tree->doc != doc) {
2785
xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
2786
xmlDictPtr newDict = doc ? doc->dict : NULL;
2787
2788
if(tree->type == XML_ELEMENT_NODE) {
2789
prop = tree->properties;
2790
while (prop != NULL) {
2791
if (prop->atype == XML_ATTRIBUTE_ID) {
2792
xmlRemoveID(tree->doc, prop);
2793
}
2794
2795
if (prop->doc != doc) {
2796
xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL;
2797
prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name);
2798
prop->doc = doc;
2799
}
2800
xmlSetListDoc(prop->children, doc);
2801
2802
/*
2803
* TODO: ID attributes should be also added to the new
2804
* document, but this breaks things like xmlReplaceNode.
2805
* The underlying problem is that xmlRemoveID is only called
2806
* if a node is destroyed, not if it's unlinked.
2807
*/
2808
#if 0
2809
if (xmlIsID(doc, tree, prop)) {
2810
xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2811
1);
2812
xmlAddID(NULL, doc, idVal, prop);
2813
}
2814
#endif
2815
2816
prop = prop->next;
2817
}
2818
}
2819
if (tree->type == XML_ENTITY_REF_NODE) {
2820
/*
2821
* Clear 'children' which points to the entity declaration
2822
* from the original document.
2823
*/
2824
tree->children = NULL;
2825
} else if (tree->children != NULL) {
2826
xmlSetListDoc(tree->children, doc);
2827
}
2828
2829
tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
2830
tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
2831
/* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
2832
tree->doc = doc;
2833
}
2834
}
2835
2836
/**
2837
* xmlSetListDoc:
2838
* @list: the first element
2839
* @doc: the document
2840
*
2841
* update all nodes in the list to point to the right document
2842
*/
2843
void
2844
xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2845
xmlNodePtr cur;
2846
2847
if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2848
return;
2849
cur = list;
2850
while (cur != NULL) {
2851
if (cur->doc != doc)
2852
xmlSetTreeDoc(cur, doc);
2853
cur = cur->next;
2854
}
2855
}
2856
2857
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2858
/**
2859
* xmlNewChild:
2860
* @parent: the parent node
2861
* @ns: a namespace if any
2862
* @name: the name of the child
2863
* @content: the XML content of the child if any.
2864
*
2865
* Creation of a new child element, added at the end of @parent children list.
2866
* @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2867
* created element inherits the namespace of @parent. If @content is non NULL,
2868
* a child list containing the TEXTs and ENTITY_REFs node will be created.
2869
* NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2870
* references. XML special chars must be escaped first by using
2871
* xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
2872
*
2873
* Returns a pointer to the new node object.
2874
*/
2875
xmlNodePtr
2876
xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2877
const xmlChar *name, const xmlChar *content) {
2878
xmlNodePtr cur, prev;
2879
2880
if (parent == NULL) {
2881
return(NULL);
2882
}
2883
2884
if (name == NULL) {
2885
return(NULL);
2886
}
2887
2888
/*
2889
* Allocate a new node
2890
*/
2891
if (parent->type == XML_ELEMENT_NODE) {
2892
if (ns == NULL)
2893
cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2894
else
2895
cur = xmlNewDocNode(parent->doc, ns, name, content);
2896
} else if ((parent->type == XML_DOCUMENT_NODE) ||
2897
(parent->type == XML_HTML_DOCUMENT_NODE)) {
2898
if (ns == NULL)
2899
cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2900
else
2901
cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2902
} else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2903
cur = xmlNewDocNode( parent->doc, ns, name, content);
2904
} else {
2905
return(NULL);
2906
}
2907
if (cur == NULL) return(NULL);
2908
2909
/*
2910
* add the new element at the end of the children list.
2911
*/
2912
cur->type = XML_ELEMENT_NODE;
2913
cur->parent = parent;
2914
cur->doc = parent->doc;
2915
if (parent->children == NULL) {
2916
parent->children = cur;
2917
parent->last = cur;
2918
} else {
2919
prev = parent->last;
2920
prev->next = cur;
2921
cur->prev = prev;
2922
parent->last = cur;
2923
}
2924
2925
return(cur);
2926
}
2927
#endif /* LIBXML_TREE_ENABLED */
2928
2929
/**
2930
* xmlAddPropSibling:
2931
* @prev: the attribute to which @prop is added after
2932
* @cur: the base attribute passed to calling function
2933
* @prop: the new attribute
2934
*
2935
* Add a new attribute after @prev using @cur as base attribute.
2936
* When inserting before @cur, @prev is passed as @cur->prev.
2937
* When inserting after @cur, @prev is passed as @cur.
2938
* If an existing attribute is found it is destroyed prior to adding @prop.
2939
*
2940
* See the note regarding namespaces in xmlAddChild.
2941
*
2942
* Returns the attribute being inserted or NULL in case of error.
2943
*/
2944
static xmlNodePtr
2945
xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2946
xmlAttrPtr attr;
2947
2948
if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2949
(prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2950
((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
2951
return(NULL);
2952
2953
/* check if an attribute with the same name exists */
2954
if (prop->ns == NULL)
2955
attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2956
else
2957
attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2958
2959
if (prop->doc != cur->doc) {
2960
xmlSetTreeDoc(prop, cur->doc);
2961
}
2962
prop->parent = cur->parent;
2963
prop->prev = prev;
2964
if (prev != NULL) {
2965
prop->next = prev->next;
2966
prev->next = prop;
2967
if (prop->next)
2968
prop->next->prev = prop;
2969
} else {
2970
prop->next = cur;
2971
cur->prev = prop;
2972
}
2973
if (prop->prev == NULL && prop->parent != NULL)
2974
prop->parent->properties = (xmlAttrPtr) prop;
2975
if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2976
/* different instance, destroy it (attributes must be unique) */
2977
xmlRemoveProp((xmlAttrPtr) attr);
2978
}
2979
return prop;
2980
}
2981
2982
/**
2983
* xmlAddNextSibling:
2984
* @cur: the child node
2985
* @elem: the new node
2986
*
2987
* Add a new node @elem as the next sibling of @cur
2988
* If the new node was already inserted in a document it is
2989
* first unlinked from its existing context.
2990
* As a result of text merging @elem may be freed.
2991
* If the new node is ATTRIBUTE, it is added into properties instead of children.
2992
* If there is an attribute with equal name, it is first destroyed.
2993
*
2994
* See the note regarding namespaces in xmlAddChild.
2995
*
2996
* Returns the new node or NULL in case of error.
2997
*/
2998
xmlNodePtr
2999
xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
3000
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3001
return(NULL);
3002
}
3003
if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3004
return(NULL);
3005
}
3006
3007
if (cur == elem) {
3008
return(NULL);
3009
}
3010
3011
xmlUnlinkNode(elem);
3012
3013
if (elem->type == XML_TEXT_NODE) {
3014
if (cur->type == XML_TEXT_NODE) {
3015
xmlNodeAddContent(cur, elem->content);
3016
xmlFreeNode(elem);
3017
return(cur);
3018
}
3019
if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3020
(cur->name == cur->next->name)) {
3021
xmlChar *tmp;
3022
3023
tmp = xmlStrdup(elem->content);
3024
tmp = xmlStrcat(tmp, cur->next->content);
3025
xmlNodeSetContent(cur->next, tmp);
3026
xmlFree(tmp);
3027
xmlFreeNode(elem);
3028
return(cur->next);
3029
}
3030
} else if (elem->type == XML_ATTRIBUTE_NODE) {
3031
return xmlAddPropSibling(cur, cur, elem);
3032
}
3033
3034
if (elem->doc != cur->doc) {
3035
xmlSetTreeDoc(elem, cur->doc);
3036
}
3037
elem->parent = cur->parent;
3038
elem->prev = cur;
3039
elem->next = cur->next;
3040
cur->next = elem;
3041
if (elem->next != NULL)
3042
elem->next->prev = elem;
3043
if ((elem->parent != NULL) && (elem->parent->last == cur))
3044
elem->parent->last = elem;
3045
return(elem);
3046
}
3047
3048
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3049
defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3050
/**
3051
* xmlAddPrevSibling:
3052
* @cur: the child node
3053
* @elem: the new node
3054
*
3055
* Add a new node @elem as the previous sibling of @cur
3056
* merging adjacent TEXT nodes (@elem may be freed)
3057
* If the new node was already inserted in a document it is
3058
* first unlinked from its existing context.
3059
* If the new node is ATTRIBUTE, it is added into properties instead of children.
3060
* If there is an attribute with equal name, it is first destroyed.
3061
*
3062
* See the note regarding namespaces in xmlAddChild.
3063
*
3064
* Returns the new node or NULL in case of error.
3065
*/
3066
xmlNodePtr
3067
xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3068
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3069
return(NULL);
3070
}
3071
if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3072
return(NULL);
3073
}
3074
3075
if (cur == elem) {
3076
return(NULL);
3077
}
3078
3079
xmlUnlinkNode(elem);
3080
3081
if (elem->type == XML_TEXT_NODE) {
3082
if (cur->type == XML_TEXT_NODE) {
3083
xmlChar *tmp;
3084
3085
tmp = xmlStrdup(elem->content);
3086
tmp = xmlStrcat(tmp, cur->content);
3087
xmlNodeSetContent(cur, tmp);
3088
xmlFree(tmp);
3089
xmlFreeNode(elem);
3090
return(cur);
3091
}
3092
if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3093
(cur->name == cur->prev->name)) {
3094
xmlNodeAddContent(cur->prev, elem->content);
3095
xmlFreeNode(elem);
3096
return(cur->prev);
3097
}
3098
} else if (elem->type == XML_ATTRIBUTE_NODE) {
3099
return xmlAddPropSibling(cur->prev, cur, elem);
3100
}
3101
3102
if (elem->doc != cur->doc) {
3103
xmlSetTreeDoc(elem, cur->doc);
3104
}
3105
elem->parent = cur->parent;
3106
elem->next = cur;
3107
elem->prev = cur->prev;
3108
cur->prev = elem;
3109
if (elem->prev != NULL)
3110
elem->prev->next = elem;
3111
if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3112
elem->parent->children = elem;
3113
}
3114
return(elem);
3115
}
3116
#endif /* LIBXML_TREE_ENABLED */
3117
3118
/**
3119
* xmlAddSibling:
3120
* @cur: the child node
3121
* @elem: the new node
3122
*
3123
* Add a new element @elem to the list of siblings of @cur
3124
* merging adjacent TEXT nodes (@elem may be freed)
3125
* If the new element was already inserted in a document it is
3126
* first unlinked from its existing context.
3127
*
3128
* See the note regarding namespaces in xmlAddChild.
3129
*
3130
* Returns the new element or NULL in case of error.
3131
*/
3132
xmlNodePtr
3133
xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3134
xmlNodePtr parent;
3135
3136
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3137
return(NULL);
3138
}
3139
3140
if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3141
return(NULL);
3142
}
3143
3144
if (cur == elem) {
3145
return(NULL);
3146
}
3147
3148
/*
3149
* Constant time is we can rely on the ->parent->last to find
3150
* the last sibling.
3151
*/
3152
if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3153
(cur->parent->children != NULL) &&
3154
(cur->parent->last != NULL) &&
3155
(cur->parent->last->next == NULL)) {
3156
cur = cur->parent->last;
3157
} else {
3158
while (cur->next != NULL) cur = cur->next;
3159
}
3160
3161
xmlUnlinkNode(elem);
3162
3163
if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3164
(cur->name == elem->name)) {
3165
xmlNodeAddContent(cur, elem->content);
3166
xmlFreeNode(elem);
3167
return(cur);
3168
} else if (elem->type == XML_ATTRIBUTE_NODE) {
3169
return xmlAddPropSibling(cur, cur, elem);
3170
}
3171
3172
if (elem->doc != cur->doc) {
3173
xmlSetTreeDoc(elem, cur->doc);
3174
}
3175
parent = cur->parent;
3176
elem->prev = cur;
3177
elem->next = NULL;
3178
elem->parent = parent;
3179
cur->next = elem;
3180
if (parent != NULL)
3181
parent->last = elem;
3182
3183
return(elem);
3184
}
3185
3186
/**
3187
* xmlAddChildList:
3188
* @parent: the parent node
3189
* @cur: the first node in the list
3190
*
3191
* Add a list of node at the end of the child list of the parent
3192
* merging adjacent TEXT nodes (@cur may be freed)
3193
*
3194
* See the note regarding namespaces in xmlAddChild.
3195
*
3196
* Returns the last child or NULL in case of error.
3197
*/
3198
xmlNodePtr
3199
xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3200
xmlNodePtr prev;
3201
3202
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3203
return(NULL);
3204
}
3205
3206
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3207
return(NULL);
3208
}
3209
3210
if ((cur->doc != NULL) && (parent->doc != NULL) &&
3211
(cur->doc != parent->doc)) {
3212
}
3213
3214
/*
3215
* add the first element at the end of the children list.
3216
*/
3217
3218
if (parent->children == NULL) {
3219
parent->children = cur;
3220
} else {
3221
/*
3222
* If cur and parent->last both are TEXT nodes, then merge them.
3223
*/
3224
if ((cur->type == XML_TEXT_NODE) &&
3225
(parent->last->type == XML_TEXT_NODE) &&
3226
(cur->name == parent->last->name)) {
3227
xmlNodeAddContent(parent->last, cur->content);
3228
/*
3229
* if it's the only child, nothing more to be done.
3230
*/
3231
if (cur->next == NULL) {
3232
xmlFreeNode(cur);
3233
return(parent->last);
3234
}
3235
prev = cur;
3236
cur = cur->next;
3237
xmlFreeNode(prev);
3238
}
3239
prev = parent->last;
3240
prev->next = cur;
3241
cur->prev = prev;
3242
}
3243
while (cur->next != NULL) {
3244
cur->parent = parent;
3245
if (cur->doc != parent->doc) {
3246
xmlSetTreeDoc(cur, parent->doc);
3247
}
3248
cur = cur->next;
3249
}
3250
cur->parent = parent;
3251
/* the parent may not be linked to a doc ! */
3252
if (cur->doc != parent->doc) {
3253
xmlSetTreeDoc(cur, parent->doc);
3254
}
3255
parent->last = cur;
3256
3257
return(cur);
3258
}
3259
3260
/**
3261
* xmlAddChild:
3262
* @parent: the parent node
3263
* @cur: the child node
3264
*
3265
* Add a new node to @parent, at the end of the child (or property) list
3266
* merging adjacent TEXT nodes (in which case @cur is freed)
3267
* If the new node is ATTRIBUTE, it is added into properties instead of children.
3268
* If there is an attribute with equal name, it is first destroyed.
3269
*
3270
* All tree manipulation functions can safely move nodes within a document.
3271
* But when moving nodes from one document to another, references to
3272
* namespaces in element or attribute nodes are NOT fixed. In this case,
3273
* you MUST call xmlReconciliateNs after the move operation to avoid
3274
* memory errors.
3275
*
3276
* Returns the child or NULL in case of error.
3277
*/
3278
xmlNodePtr
3279
xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3280
xmlNodePtr prev;
3281
3282
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3283
return(NULL);
3284
}
3285
3286
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3287
return(NULL);
3288
}
3289
3290
if (parent == cur) {
3291
return(NULL);
3292
}
3293
/*
3294
* If cur is a TEXT node, merge its content with adjacent TEXT nodes
3295
* cur is then freed.
3296
*/
3297
if (cur->type == XML_TEXT_NODE) {
3298
if ((parent->type == XML_TEXT_NODE) &&
3299
(parent->content != NULL) &&
3300
(parent->name == cur->name)) {
3301
xmlNodeAddContent(parent, cur->content);
3302
xmlFreeNode(cur);
3303
return(parent);
3304
}
3305
if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3306
(parent->last->name == cur->name) &&
3307
(parent->last != cur)) {
3308
xmlNodeAddContent(parent->last, cur->content);
3309
xmlFreeNode(cur);
3310
return(parent->last);
3311
}
3312
}
3313
3314
/*
3315
* add the new element at the end of the children list.
3316
*/
3317
prev = cur->parent;
3318
cur->parent = parent;
3319
if (cur->doc != parent->doc) {
3320
xmlSetTreeDoc(cur, parent->doc);
3321
}
3322
/* this check prevents a loop on tree-traversions if a developer
3323
* tries to add a node to its parent multiple times
3324
*/
3325
if (prev == parent)
3326
return(cur);
3327
3328
/*
3329
* Coalescing
3330
*/
3331
if ((parent->type == XML_TEXT_NODE) &&
3332
(parent->content != NULL) &&
3333
(parent != cur)) {
3334
xmlNodeAddContent(parent, cur->content);
3335
xmlFreeNode(cur);
3336
return(parent);
3337
}
3338
if (cur->type == XML_ATTRIBUTE_NODE) {
3339
if (parent->type != XML_ELEMENT_NODE)
3340
return(NULL);
3341
if (parent->properties != NULL) {
3342
/* check if an attribute with the same name exists */
3343
xmlAttrPtr lastattr;
3344
3345
if (cur->ns == NULL)
3346
lastattr = xmlHasNsProp(parent, cur->name, NULL);
3347
else
3348
lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3349
if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3350
/* different instance, destroy it (attributes must be unique) */
3351
xmlUnlinkNode((xmlNodePtr) lastattr);
3352
xmlFreeProp(lastattr);
3353
}
3354
if (lastattr == (xmlAttrPtr) cur)
3355
return(cur);
3356
3357
}
3358
if (parent->properties == NULL) {
3359
parent->properties = (xmlAttrPtr) cur;
3360
} else {
3361
/* find the end */
3362
xmlAttrPtr lastattr = parent->properties;
3363
while (lastattr->next != NULL) {
3364
lastattr = lastattr->next;
3365
}
3366
lastattr->next = (xmlAttrPtr) cur;
3367
((xmlAttrPtr) cur)->prev = lastattr;
3368
}
3369
} else {
3370
if (parent->children == NULL) {
3371
parent->children = cur;
3372
parent->last = cur;
3373
} else {
3374
prev = parent->last;
3375
prev->next = cur;
3376
cur->prev = prev;
3377
parent->last = cur;
3378
}
3379
}
3380
return(cur);
3381
}
3382
3383
/**
3384
* xmlGetLastChild:
3385
* @parent: the parent node
3386
*
3387
* Search the last child of a node.
3388
* Returns the last child or NULL if none.
3389
*/
3390
xmlNodePtr
3391
xmlGetLastChild(const xmlNode *parent) {
3392
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3393
return(NULL);
3394
}
3395
return(parent->last);
3396
}
3397
3398
#ifdef LIBXML_TREE_ENABLED
3399
/*
3400
* 5 interfaces from DOM ElementTraversal
3401
*/
3402
3403
/**
3404
* xmlChildElementCount:
3405
* @parent: the parent node
3406
*
3407
* Finds the current number of child nodes of that element which are
3408
* element nodes.
3409
* Note the handling of entities references is different than in
3410
* the W3C DOM element traversal spec since we don't have back reference
3411
* from entities content to entities references.
3412
*
3413
* Returns the count of element child or 0 if not available
3414
*/
3415
unsigned long
3416
xmlChildElementCount(xmlNodePtr parent) {
3417
unsigned long ret = 0;
3418
xmlNodePtr cur = NULL;
3419
3420
if (parent == NULL)
3421
return(0);
3422
switch (parent->type) {
3423
case XML_ELEMENT_NODE:
3424
case XML_ENTITY_NODE:
3425
case XML_DOCUMENT_NODE:
3426
case XML_DOCUMENT_FRAG_NODE:
3427
case XML_HTML_DOCUMENT_NODE:
3428
cur = parent->children;
3429
break;
3430
default:
3431
return(0);
3432
}
3433
while (cur != NULL) {
3434
if (cur->type == XML_ELEMENT_NODE)
3435
ret++;
3436
cur = cur->next;
3437
}
3438
return(ret);
3439
}
3440
3441
/**
3442
* xmlFirstElementChild:
3443
* @parent: the parent node
3444
*
3445
* Finds the first child node of that element which is a Element node
3446
* Note the handling of entities references is different than in
3447
* the W3C DOM element traversal spec since we don't have back reference
3448
* from entities content to entities references.
3449
*
3450
* Returns the first element child or NULL if not available
3451
*/
3452
xmlNodePtr
3453
xmlFirstElementChild(xmlNodePtr parent) {
3454
xmlNodePtr cur = NULL;
3455
3456
if (parent == NULL)
3457
return(NULL);
3458
switch (parent->type) {
3459
case XML_ELEMENT_NODE:
3460
case XML_ENTITY_NODE:
3461
case XML_DOCUMENT_NODE:
3462
case XML_DOCUMENT_FRAG_NODE:
3463
case XML_HTML_DOCUMENT_NODE:
3464
cur = parent->children;
3465
break;
3466
default:
3467
return(NULL);
3468
}
3469
while (cur != NULL) {
3470
if (cur->type == XML_ELEMENT_NODE)
3471
return(cur);
3472
cur = cur->next;
3473
}
3474
return(NULL);
3475
}
3476
3477
/**
3478
* xmlLastElementChild:
3479
* @parent: the parent node
3480
*
3481
* Finds the last child node of that element which is a Element node
3482
* Note the handling of entities references is different than in
3483
* the W3C DOM element traversal spec since we don't have back reference
3484
* from entities content to entities references.
3485
*
3486
* Returns the last element child or NULL if not available
3487
*/
3488
xmlNodePtr
3489
xmlLastElementChild(xmlNodePtr parent) {
3490
xmlNodePtr cur = NULL;
3491
3492
if (parent == NULL)
3493
return(NULL);
3494
switch (parent->type) {
3495
case XML_ELEMENT_NODE:
3496
case XML_ENTITY_NODE:
3497
case XML_DOCUMENT_NODE:
3498
case XML_DOCUMENT_FRAG_NODE:
3499
case XML_HTML_DOCUMENT_NODE:
3500
cur = parent->last;
3501
break;
3502
default:
3503
return(NULL);
3504
}
3505
while (cur != NULL) {
3506
if (cur->type == XML_ELEMENT_NODE)
3507
return(cur);
3508
cur = cur->prev;
3509
}
3510
return(NULL);
3511
}
3512
3513
/**
3514
* xmlPreviousElementSibling:
3515
* @node: the current node
3516
*
3517
* Finds the first closest previous sibling of the node which is an
3518
* element node.
3519
* Note the handling of entities references is different than in
3520
* the W3C DOM element traversal spec since we don't have back reference
3521
* from entities content to entities references.
3522
*
3523
* Returns the previous element sibling or NULL if not available
3524
*/
3525
xmlNodePtr
3526
xmlPreviousElementSibling(xmlNodePtr node) {
3527
if (node == NULL)
3528
return(NULL);
3529
switch (node->type) {
3530
case XML_ELEMENT_NODE:
3531
case XML_TEXT_NODE:
3532
case XML_CDATA_SECTION_NODE:
3533
case XML_ENTITY_REF_NODE:
3534
case XML_ENTITY_NODE:
3535
case XML_PI_NODE:
3536
case XML_COMMENT_NODE:
3537
case XML_XINCLUDE_START:
3538
case XML_XINCLUDE_END:
3539
node = node->prev;
3540
break;
3541
default:
3542
return(NULL);
3543
}
3544
while (node != NULL) {
3545
if (node->type == XML_ELEMENT_NODE)
3546
return(node);
3547
node = node->prev;
3548
}
3549
return(NULL);
3550
}
3551
3552
/**
3553
* xmlNextElementSibling:
3554
* @node: the current node
3555
*
3556
* Finds the first closest next sibling of the node which is an
3557
* element node.
3558
* Note the handling of entities references is different than in
3559
* the W3C DOM element traversal spec since we don't have back reference
3560
* from entities content to entities references.
3561
*
3562
* Returns the next element sibling or NULL if not available
3563
*/
3564
xmlNodePtr
3565
xmlNextElementSibling(xmlNodePtr node) {
3566
if (node == NULL)
3567
return(NULL);
3568
switch (node->type) {
3569
case XML_ELEMENT_NODE:
3570
case XML_TEXT_NODE:
3571
case XML_CDATA_SECTION_NODE:
3572
case XML_ENTITY_REF_NODE:
3573
case XML_ENTITY_NODE:
3574
case XML_PI_NODE:
3575
case XML_COMMENT_NODE:
3576
case XML_DTD_NODE:
3577
case XML_XINCLUDE_START:
3578
case XML_XINCLUDE_END:
3579
node = node->next;
3580
break;
3581
default:
3582
return(NULL);
3583
}
3584
while (node != NULL) {
3585
if (node->type == XML_ELEMENT_NODE)
3586
return(node);
3587
node = node->next;
3588
}
3589
return(NULL);
3590
}
3591
3592
#endif /* LIBXML_TREE_ENABLED */
3593
3594
/**
3595
* xmlFreeNodeList:
3596
* @cur: the first node in the list
3597
*
3598
* Free a node and all its siblings, this is a recursive behaviour, all
3599
* the children are freed too.
3600
*/
3601
void
3602
xmlFreeNodeList(xmlNodePtr cur) {
3603
xmlNodePtr next;
3604
xmlNodePtr parent;
3605
xmlDictPtr dict = NULL;
3606
size_t depth = 0;
3607
3608
if (cur == NULL) return;
3609
if (cur->type == XML_NAMESPACE_DECL) {
3610
xmlFreeNsList((xmlNsPtr) cur);
3611
return;
3612
}
3613
if (cur->doc != NULL) dict = cur->doc->dict;
3614
while (1) {
3615
while ((cur->children != NULL) &&
3616
(cur->type != XML_DOCUMENT_NODE) &&
3617
(cur->type != XML_HTML_DOCUMENT_NODE) &&
3618
(cur->type != XML_DTD_NODE) &&
3619
(cur->type != XML_ENTITY_REF_NODE)) {
3620
cur = cur->children;
3621
depth += 1;
3622
}
3623
3624
next = cur->next;
3625
parent = cur->parent;
3626
if ((cur->type == XML_DOCUMENT_NODE) ||
3627
(cur->type == XML_HTML_DOCUMENT_NODE)) {
3628
xmlFreeDoc((xmlDocPtr) cur);
3629
} else if (cur->type != XML_DTD_NODE) {
3630
3631
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3632
xmlDeregisterNodeDefaultValue(cur);
3633
3634
if (((cur->type == XML_ELEMENT_NODE) ||
3635
(cur->type == XML_XINCLUDE_START) ||
3636
(cur->type == XML_XINCLUDE_END)) &&
3637
(cur->properties != NULL))
3638
xmlFreePropList(cur->properties);
3639
if ((cur->type != XML_ELEMENT_NODE) &&
3640
(cur->type != XML_XINCLUDE_START) &&
3641
(cur->type != XML_XINCLUDE_END) &&
3642
(cur->type != XML_ENTITY_REF_NODE) &&
3643
(cur->content != (xmlChar *) &(cur->properties))) {
3644
DICT_FREE(cur->content)
3645
}
3646
if (((cur->type == XML_ELEMENT_NODE) ||
3647
(cur->type == XML_XINCLUDE_START) ||
3648
(cur->type == XML_XINCLUDE_END)) &&
3649
(cur->nsDef != NULL))
3650
xmlFreeNsList(cur->nsDef);
3651
3652
/*
3653
* When a node is a text node or a comment, it uses a global static
3654
* variable for the name of the node.
3655
* Otherwise the node name might come from the document's
3656
* dictionary
3657
*/
3658
if ((cur->name != NULL) &&
3659
(cur->type != XML_TEXT_NODE) &&
3660
(cur->type != XML_COMMENT_NODE))
3661
DICT_FREE(cur->name)
3662
xmlFree(cur);
3663
}
3664
3665
if (next != NULL) {
3666
cur = next;
3667
} else {
3668
if ((depth == 0) || (parent == NULL))
3669
break;
3670
depth -= 1;
3671
cur = parent;
3672
cur->children = NULL;
3673
}
3674
}
3675
}
3676
3677
/**
3678
* xmlFreeNode:
3679
* @cur: the node
3680
*
3681
* Free a node, this is a recursive behaviour, all the children are freed too.
3682
* This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3683
*/
3684
void
3685
xmlFreeNode(xmlNodePtr cur) {
3686
xmlDictPtr dict = NULL;
3687
3688
if (cur == NULL) return;
3689
3690
/* use xmlFreeDtd for DTD nodes */
3691
if (cur->type == XML_DTD_NODE) {
3692
xmlFreeDtd((xmlDtdPtr) cur);
3693
return;
3694
}
3695
if (cur->type == XML_NAMESPACE_DECL) {
3696
xmlFreeNs((xmlNsPtr) cur);
3697
return;
3698
}
3699
if (cur->type == XML_ATTRIBUTE_NODE) {
3700
xmlFreeProp((xmlAttrPtr) cur);
3701
return;
3702
}
3703
3704
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3705
xmlDeregisterNodeDefaultValue(cur);
3706
3707
if (cur->doc != NULL) dict = cur->doc->dict;
3708
3709
if (cur->type == XML_ENTITY_DECL) {
3710
xmlEntityPtr ent = (xmlEntityPtr) cur;
3711
DICT_FREE(ent->SystemID);
3712
DICT_FREE(ent->ExternalID);
3713
}
3714
if ((cur->children != NULL) &&
3715
(cur->type != XML_ENTITY_REF_NODE))
3716
xmlFreeNodeList(cur->children);
3717
3718
if ((cur->type == XML_ELEMENT_NODE) ||
3719
(cur->type == XML_XINCLUDE_START) ||
3720
(cur->type == XML_XINCLUDE_END)) {
3721
if (cur->properties != NULL)
3722
xmlFreePropList(cur->properties);
3723
if (cur->nsDef != NULL)
3724
xmlFreeNsList(cur->nsDef);
3725
} else if ((cur->content != NULL) &&
3726
(cur->type != XML_ENTITY_REF_NODE) &&
3727
(cur->content != (xmlChar *) &(cur->properties))) {
3728
DICT_FREE(cur->content)
3729
}
3730
3731
/*
3732
* When a node is a text node or a comment, it uses a global static
3733
* variable for the name of the node.
3734
* Otherwise the node name might come from the document's dictionary
3735
*/
3736
if ((cur->name != NULL) &&
3737
(cur->type != XML_TEXT_NODE) &&
3738
(cur->type != XML_COMMENT_NODE))
3739
DICT_FREE(cur->name)
3740
3741
xmlFree(cur);
3742
}
3743
3744
/**
3745
* xmlUnlinkNode:
3746
* @cur: the node
3747
*
3748
* Unlink a node from it's current context, the node is not freed
3749
* If one need to free the node, use xmlFreeNode() routine after the
3750
* unlink to discard it.
3751
* Note that namespace nodes can't be unlinked as they do not have
3752
* pointer to their parent.
3753
*/
3754
void
3755
xmlUnlinkNode(xmlNodePtr cur) {
3756
if (cur == NULL) {
3757
return;
3758
}
3759
if (cur->type == XML_NAMESPACE_DECL)
3760
return;
3761
if (cur->type == XML_DTD_NODE) {
3762
xmlDocPtr doc;
3763
doc = cur->doc;
3764
if (doc != NULL) {
3765
if (doc->intSubset == (xmlDtdPtr) cur)
3766
doc->intSubset = NULL;
3767
if (doc->extSubset == (xmlDtdPtr) cur)
3768
doc->extSubset = NULL;
3769
}
3770
}
3771
if (cur->type == XML_ENTITY_DECL) {
3772
xmlDocPtr doc;
3773
doc = cur->doc;
3774
if (doc != NULL) {
3775
if (doc->intSubset != NULL) {
3776
if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3777
xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3778
NULL);
3779
if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3780
xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3781
NULL);
3782
}
3783
if (doc->extSubset != NULL) {
3784
if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3785
xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3786
NULL);
3787
if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3788
xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3789
NULL);
3790
}
3791
}
3792
}
3793
if (cur->parent != NULL) {
3794
xmlNodePtr parent;
3795
parent = cur->parent;
3796
if (cur->type == XML_ATTRIBUTE_NODE) {
3797
if (parent->properties == (xmlAttrPtr) cur)
3798
parent->properties = ((xmlAttrPtr) cur)->next;
3799
} else {
3800
if (parent->children == cur)
3801
parent->children = cur->next;
3802
if (parent->last == cur)
3803
parent->last = cur->prev;
3804
}
3805
cur->parent = NULL;
3806
}
3807
if (cur->next != NULL)
3808
cur->next->prev = cur->prev;
3809
if (cur->prev != NULL)
3810
cur->prev->next = cur->next;
3811
cur->next = cur->prev = NULL;
3812
}
3813
3814
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3815
/**
3816
* xmlReplaceNode:
3817
* @old: the old node
3818
* @cur: the node
3819
*
3820
* Unlink the old node from its current context, prune the new one
3821
* at the same place. If @cur was already inserted in a document it is
3822
* first unlinked from its existing context.
3823
*
3824
* See the note regarding namespaces in xmlAddChild.
3825
*
3826
* Returns the @old node
3827
*/
3828
xmlNodePtr
3829
xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3830
if (old == cur) return(NULL);
3831
if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3832
(old->parent == NULL)) {
3833
return(NULL);
3834
}
3835
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3836
xmlUnlinkNode(old);
3837
return(old);
3838
}
3839
if (cur == old) {
3840
return(old);
3841
}
3842
if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3843
return(old);
3844
}
3845
if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3846
return(old);
3847
}
3848
xmlUnlinkNode(cur);
3849
xmlSetTreeDoc(cur, old->doc);
3850
cur->parent = old->parent;
3851
cur->next = old->next;
3852
if (cur->next != NULL)
3853
cur->next->prev = cur;
3854
cur->prev = old->prev;
3855
if (cur->prev != NULL)
3856
cur->prev->next = cur;
3857
if (cur->parent != NULL) {
3858
if (cur->type == XML_ATTRIBUTE_NODE) {
3859
if (cur->parent->properties == (xmlAttrPtr)old)
3860
cur->parent->properties = ((xmlAttrPtr) cur);
3861
} else {
3862
if (cur->parent->children == old)
3863
cur->parent->children = cur;
3864
if (cur->parent->last == old)
3865
cur->parent->last = cur;
3866
}
3867
}
3868
old->next = old->prev = NULL;
3869
old->parent = NULL;
3870
return(old);
3871
}
3872
#endif /* LIBXML_TREE_ENABLED */
3873
3874
/************************************************************************
3875
* *
3876
* Copy operations *
3877
* *
3878
************************************************************************/
3879
3880
/**
3881
* xmlCopyNamespace:
3882
* @cur: the namespace
3883
*
3884
* Do a copy of the namespace.
3885
*
3886
* Returns: a new #xmlNsPtr, or NULL in case of error.
3887
*/
3888
xmlNsPtr
3889
xmlCopyNamespace(xmlNsPtr cur) {
3890
xmlNsPtr ret;
3891
3892
if (cur == NULL) return(NULL);
3893
switch (cur->type) {
3894
case XML_LOCAL_NAMESPACE:
3895
ret = xmlNewNs(NULL, cur->href, cur->prefix);
3896
break;
3897
default:
3898
return(NULL);
3899
}
3900
return(ret);
3901
}
3902
3903
/**
3904
* xmlCopyNamespaceList:
3905
* @cur: the first namespace
3906
*
3907
* Do a copy of an namespace list.
3908
*
3909
* Returns: a new #xmlNsPtr, or NULL in case of error.
3910
*/
3911
xmlNsPtr
3912
xmlCopyNamespaceList(xmlNsPtr cur) {
3913
xmlNsPtr ret = NULL;
3914
xmlNsPtr p = NULL,q;
3915
3916
while (cur != NULL) {
3917
q = xmlCopyNamespace(cur);
3918
if (q == NULL) {
3919
xmlFreeNsList(ret);
3920
return(NULL);
3921
}
3922
if (p == NULL) {
3923
ret = p = q;
3924
} else {
3925
p->next = q;
3926
p = q;
3927
}
3928
cur = cur->next;
3929
}
3930
return(ret);
3931
}
3932
3933
static xmlAttrPtr
3934
xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
3935
xmlAttrPtr ret;
3936
3937
if (cur == NULL) return(NULL);
3938
if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
3939
return(NULL);
3940
if (target != NULL)
3941
ret = xmlNewDocProp(target->doc, cur->name, NULL);
3942
else if (doc != NULL)
3943
ret = xmlNewDocProp(doc, cur->name, NULL);
3944
else if (cur->parent != NULL)
3945
ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3946
else if (cur->children != NULL)
3947
ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3948
else
3949
ret = xmlNewDocProp(NULL, cur->name, NULL);
3950
if (ret == NULL) return(NULL);
3951
ret->parent = target;
3952
3953
if ((cur->ns != NULL) && (target != NULL)) {
3954
xmlNsPtr ns;
3955
3956
ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3957
if (ns == NULL) {
3958
/*
3959
* Humm, we are copying an element whose namespace is defined
3960
* out of the new tree scope. Search it in the original tree
3961
* and add it at the top of the new tree
3962
*/
3963
ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3964
if (ns != NULL) {
3965
xmlNodePtr root = target;
3966
xmlNodePtr pred = NULL;
3967
3968
while (root->parent != NULL) {
3969
pred = root;
3970
root = root->parent;
3971
}
3972
if (root == (xmlNodePtr) target->doc) {
3973
/* correct possibly cycling above the document elt */
3974
root = pred;
3975
}
3976
ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3977
}
3978
} else {
3979
/*
3980
* we have to find something appropriate here since
3981
* we can't be sure, that the namespace we found is identified
3982
* by the prefix
3983
*/
3984
if (xmlStrEqual(ns->href, cur->ns->href)) {
3985
/* this is the nice case */
3986
ret->ns = ns;
3987
} else {
3988
/*
3989
* we are in trouble: we need a new reconciled namespace.
3990
* This is expensive
3991
*/
3992
ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
3993
}
3994
}
3995
3996
} else
3997
ret->ns = NULL;
3998
3999
if (cur->children != NULL) {
4000
xmlNodePtr tmp;
4001
4002
ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4003
ret->last = NULL;
4004
tmp = ret->children;
4005
while (tmp != NULL) {
4006
/* tmp->parent = (xmlNodePtr)ret; */
4007
if (tmp->next == NULL)
4008
ret->last = tmp;
4009
tmp = tmp->next;
4010
}
4011
}
4012
/*
4013
* Try to handle IDs
4014
*/
4015
if ((target!= NULL) && (cur!= NULL) &&
4016
(target->doc != NULL) && (cur->doc != NULL) &&
4017
(cur->doc->ids != NULL) && (cur->parent != NULL)) {
4018
if (xmlIsID(cur->doc, cur->parent, cur)) {
4019
xmlChar *id;
4020
4021
id = xmlNodeListGetString(cur->doc, cur->children, 1);
4022
if (id != NULL) {
4023
xmlAddID(NULL, target->doc, id, ret);
4024
xmlFree(id);
4025
}
4026
}
4027
}
4028
return(ret);
4029
}
4030
4031
/**
4032
* xmlCopyProp:
4033
* @target: the element where the attribute will be grafted
4034
* @cur: the attribute
4035
*
4036
* Do a copy of the attribute.
4037
*
4038
* Returns: a new #xmlAttrPtr, or NULL in case of error.
4039
*/
4040
xmlAttrPtr
4041
xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4042
return xmlCopyPropInternal(NULL, target, cur);
4043
}
4044
4045
/**
4046
* xmlCopyPropList:
4047
* @target: the element where the attributes will be grafted
4048
* @cur: the first attribute
4049
*
4050
* Do a copy of an attribute list.
4051
*
4052
* Returns: a new #xmlAttrPtr, or NULL in case of error.
4053
*/
4054
xmlAttrPtr
4055
xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4056
xmlAttrPtr ret = NULL;
4057
xmlAttrPtr p = NULL,q;
4058
4059
if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4060
return(NULL);
4061
while (cur != NULL) {
4062
q = xmlCopyProp(target, cur);
4063
if (q == NULL) {
4064
xmlFreePropList(ret);
4065
return(NULL);
4066
}
4067
if (p == NULL) {
4068
ret = p = q;
4069
} else {
4070
p->next = q;
4071
q->prev = p;
4072
p = q;
4073
}
4074
cur = cur->next;
4075
}
4076
return(ret);
4077
}
4078
4079
/*
4080
* NOTE about the CopyNode operations !
4081
*
4082
* They are split into external and internal parts for one
4083
* tricky reason: namespaces. Doing a direct copy of a node
4084
* say RPM:Copyright without changing the namespace pointer to
4085
* something else can produce stale links. One way to do it is
4086
* to keep a reference counter but this doesn't work as soon
4087
* as one moves the element or the subtree out of the scope of
4088
* the existing namespace. The actual solution seems to be to add
4089
* a copy of the namespace at the top of the copied tree if
4090
* not available in the subtree.
4091
* Hence two functions, the public front-end call the inner ones
4092
* The argument "recursive" normally indicates a recursive copy
4093
* of the node with values 0 (no) and 1 (yes). For XInclude,
4094
* however, we allow a value of 2 to indicate copy properties and
4095
* namespace info, but don't recurse on children.
4096
*/
4097
4098
xmlNodePtr
4099
xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4100
int extended) {
4101
xmlNodePtr ret;
4102
4103
if (node == NULL) return(NULL);
4104
switch (node->type) {
4105
case XML_TEXT_NODE:
4106
case XML_CDATA_SECTION_NODE:
4107
case XML_ELEMENT_NODE:
4108
case XML_DOCUMENT_FRAG_NODE:
4109
case XML_ENTITY_REF_NODE:
4110
case XML_ENTITY_NODE:
4111
case XML_PI_NODE:
4112
case XML_COMMENT_NODE:
4113
case XML_XINCLUDE_START:
4114
case XML_XINCLUDE_END:
4115
break;
4116
case XML_ATTRIBUTE_NODE:
4117
return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4118
case XML_NAMESPACE_DECL:
4119
return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
4120
4121
case XML_DOCUMENT_NODE:
4122
case XML_HTML_DOCUMENT_NODE:
4123
#ifdef LIBXML_TREE_ENABLED
4124
return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4125
#endif /* LIBXML_TREE_ENABLED */
4126
case XML_DOCUMENT_TYPE_NODE:
4127
case XML_NOTATION_NODE:
4128
case XML_DTD_NODE:
4129
case XML_ELEMENT_DECL:
4130
case XML_ATTRIBUTE_DECL:
4131
case XML_ENTITY_DECL:
4132
return(NULL);
4133
}
4134
4135
/*
4136
* Allocate a new node and fill the fields.
4137
*/
4138
ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4139
if (ret == NULL) {
4140
xmlTreeErrMemory("copying node");
4141
return(NULL);
4142
}
4143
memset(ret, 0, sizeof(xmlNode));
4144
ret->type = node->type;
4145
4146
ret->doc = doc;
4147
ret->parent = parent;
4148
if (node->name == xmlStringText)
4149
ret->name = xmlStringText;
4150
else if (node->name == xmlStringTextNoenc)
4151
ret->name = xmlStringTextNoenc;
4152
else if (node->name == xmlStringComment)
4153
ret->name = xmlStringComment;
4154
else if (node->name != NULL) {
4155
if ((doc != NULL) && (doc->dict != NULL))
4156
ret->name = xmlDictLookup(doc->dict, node->name, -1);
4157
else
4158
ret->name = xmlStrdup(node->name);
4159
}
4160
if ((node->type != XML_ELEMENT_NODE) &&
4161
(node->content != NULL) &&
4162
(node->type != XML_ENTITY_REF_NODE) &&
4163
(node->type != XML_XINCLUDE_END) &&
4164
(node->type != XML_XINCLUDE_START)) {
4165
ret->content = xmlStrdup(node->content);
4166
}else{
4167
if (node->type == XML_ELEMENT_NODE)
4168
ret->line = node->line;
4169
}
4170
if (parent != NULL) {
4171
xmlNodePtr tmp;
4172
4173
/*
4174
* this is a tricky part for the node register thing:
4175
* in case ret does get coalesced in xmlAddChild
4176
* the deregister-node callback is called; so we register ret now already
4177
*/
4178
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
4179
xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4180
4181
/*
4182
* Note that since ret->parent is already set, xmlAddChild will
4183
* return early and not actually insert the node. It will only
4184
* coalesce text nodes and unnecessarily call xmlSetTreeDoc.
4185
* Assuming that the subtree to be copied always has its text
4186
* nodes coalesced, the somewhat confusing call to xmlAddChild
4187
* could be removed.
4188
*/
4189
tmp = xmlAddChild(parent, ret);
4190
/* node could have coalesced */
4191
if (tmp != ret)
4192
return(tmp);
4193
}
4194
4195
if (!extended)
4196
goto out;
4197
if (((node->type == XML_ELEMENT_NODE) ||
4198
(node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4199
ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4200
4201
if (node->ns != NULL) {
4202
xmlNsPtr ns;
4203
4204
ns = xmlSearchNs(doc, ret, node->ns->prefix);
4205
if (ns == NULL) {
4206
/*
4207
* Humm, we are copying an element whose namespace is defined
4208
* out of the new tree scope. Search it in the original tree
4209
* and add it at the top of the new tree.
4210
*
4211
* TODO: Searching the original tree seems unnecessary. We
4212
* already have a namespace URI.
4213
*/
4214
ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4215
if (ns != NULL) {
4216
xmlNodePtr root = ret;
4217
4218
while (root->parent != NULL) root = root->parent;
4219
ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4220
} else {
4221
ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4222
}
4223
} else {
4224
/*
4225
* reference the existing namespace definition in our own tree.
4226
*/
4227
ret->ns = ns;
4228
}
4229
}
4230
if (((node->type == XML_ELEMENT_NODE) ||
4231
(node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4232
ret->properties = xmlCopyPropList(ret, node->properties);
4233
if (node->type == XML_ENTITY_REF_NODE) {
4234
if ((doc == NULL) || (node->doc != doc)) {
4235
/*
4236
* The copied node will go into a separate document, so
4237
* to avoid dangling references to the ENTITY_DECL node
4238
* we cannot keep the reference. Try to find it in the
4239
* target document.
4240
*/
4241
ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4242
} else {
4243
ret->children = node->children;
4244
}
4245
ret->last = ret->children;
4246
} else if ((node->children != NULL) && (extended != 2)) {
4247
xmlNodePtr cur, insert;
4248
4249
cur = node->children;
4250
insert = ret;
4251
while (cur != NULL) {
4252
xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2);
4253
if (copy == NULL) {
4254
xmlFreeNode(ret);
4255
return(NULL);
4256
}
4257
4258
/* Check for coalesced text nodes */
4259
if (insert->last != copy) {
4260
if (insert->last == NULL) {
4261
insert->children = copy;
4262
} else {
4263
copy->prev = insert->last;
4264
insert->last->next = copy;
4265
}
4266
insert->last = copy;
4267
}
4268
4269
if ((cur->type != XML_ENTITY_REF_NODE) &&
4270
(cur->children != NULL)) {
4271
cur = cur->children;
4272
insert = copy;
4273
continue;
4274
}
4275
4276
while (1) {
4277
if (cur->next != NULL) {
4278
cur = cur->next;
4279
break;
4280
}
4281
4282
cur = cur->parent;
4283
insert = insert->parent;
4284
if (cur == node) {
4285
cur = NULL;
4286
break;
4287
}
4288
}
4289
}
4290
}
4291
4292
out:
4293
/* if parent != NULL we already registered the node above */
4294
if ((parent == NULL) &&
4295
((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
4296
xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4297
return(ret);
4298
}
4299
4300
xmlNodePtr
4301
xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4302
xmlNodePtr ret = NULL;
4303
xmlNodePtr p = NULL,q;
4304
xmlDtdPtr newSubset = NULL;
4305
int linkedSubset = 0;
4306
4307
while (node != NULL) {
4308
#ifdef LIBXML_TREE_ENABLED
4309
if (node->type == XML_DTD_NODE ) {
4310
if (doc == NULL) {
4311
node = node->next;
4312
continue;
4313
}
4314
if ((doc->intSubset == NULL) && (newSubset == NULL)) {
4315
q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4316
if (q == NULL) goto error;
4317
q->doc = doc;
4318
q->parent = parent;
4319
newSubset = (xmlDtdPtr) q;
4320
xmlAddChild(parent, q);
4321
} else {
4322
linkedSubset = 1;
4323
q = (xmlNodePtr) doc->intSubset;
4324
xmlAddChild(parent, q);
4325
}
4326
} else
4327
#endif /* LIBXML_TREE_ENABLED */
4328
q = xmlStaticCopyNode(node, doc, parent, 1);
4329
if (q == NULL) goto error;
4330
if (ret == NULL) {
4331
q->prev = NULL;
4332
ret = p = q;
4333
} else if (p != q) {
4334
/* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4335
p->next = q;
4336
q->prev = p;
4337
p = q;
4338
}
4339
node = node->next;
4340
}
4341
if ((doc != NULL) && (newSubset != NULL))
4342
doc->intSubset = newSubset;
4343
return(ret);
4344
error:
4345
if (linkedSubset != 0)
4346
xmlUnlinkNode((xmlNodePtr) doc->intSubset);
4347
xmlFreeNodeList(ret);
4348
return(NULL);
4349
}
4350
4351
/**
4352
* xmlCopyNode:
4353
* @node: the node
4354
* @extended: if 1 do a recursive copy (properties, namespaces and children
4355
* when applicable)
4356
* if 2 copy properties and namespaces (when applicable)
4357
*
4358
* Do a copy of the node.
4359
*
4360
* Returns: a new #xmlNodePtr, or NULL in case of error.
4361
*/
4362
xmlNodePtr
4363
xmlCopyNode(xmlNodePtr node, int extended) {
4364
xmlNodePtr ret;
4365
4366
ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4367
return(ret);
4368
}
4369
4370
/**
4371
* xmlDocCopyNode:
4372
* @node: the node
4373
* @doc: the document
4374
* @extended: if 1 do a recursive copy (properties, namespaces and children
4375
* when applicable)
4376
* if 2 copy properties and namespaces (when applicable)
4377
*
4378
* Do a copy of the node to a given document.
4379
*
4380
* Returns: a new #xmlNodePtr, or NULL in case of error.
4381
*/
4382
xmlNodePtr
4383
xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4384
xmlNodePtr ret;
4385
4386
ret = xmlStaticCopyNode(node, doc, NULL, extended);
4387
return(ret);
4388
}
4389
4390
/**
4391
* xmlDocCopyNodeList:
4392
* @doc: the target document
4393
* @node: the first node in the list.
4394
*
4395
* Do a recursive copy of the node list.
4396
*
4397
* Returns: a new #xmlNodePtr, or NULL in case of error.
4398
*/
4399
xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) {
4400
xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4401
return(ret);
4402
}
4403
4404
/**
4405
* xmlCopyNodeList:
4406
* @node: the first node in the list.
4407
*
4408
* Do a recursive copy of the node list.
4409
* Use xmlDocCopyNodeList() if possible to ensure string interning.
4410
*
4411
* Returns: a new #xmlNodePtr, or NULL in case of error.
4412
*/
4413
xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
4414
xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4415
return(ret);
4416
}
4417
4418
#if defined(LIBXML_TREE_ENABLED)
4419
/**
4420
* xmlCopyDtd:
4421
* @dtd: the dtd
4422
*
4423
* Do a copy of the dtd.
4424
*
4425
* Returns: a new #xmlDtdPtr, or NULL in case of error.
4426
*/
4427
xmlDtdPtr
4428
xmlCopyDtd(xmlDtdPtr dtd) {
4429
xmlDtdPtr ret;
4430
xmlNodePtr cur, p = NULL, q;
4431
4432
if (dtd == NULL) return(NULL);
4433
ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4434
if (ret == NULL) return(NULL);
4435
if (dtd->entities != NULL)
4436
ret->entities = (void *) xmlCopyEntitiesTable(
4437
(xmlEntitiesTablePtr) dtd->entities);
4438
if (dtd->notations != NULL)
4439
ret->notations = (void *) xmlCopyNotationTable(
4440
(xmlNotationTablePtr) dtd->notations);
4441
if (dtd->elements != NULL)
4442
ret->elements = (void *) xmlCopyElementTable(
4443
(xmlElementTablePtr) dtd->elements);
4444
if (dtd->attributes != NULL)
4445
ret->attributes = (void *) xmlCopyAttributeTable(
4446
(xmlAttributeTablePtr) dtd->attributes);
4447
if (dtd->pentities != NULL)
4448
ret->pentities = (void *) xmlCopyEntitiesTable(
4449
(xmlEntitiesTablePtr) dtd->pentities);
4450
4451
cur = dtd->children;
4452
while (cur != NULL) {
4453
q = NULL;
4454
4455
if (cur->type == XML_ENTITY_DECL) {
4456
xmlEntityPtr tmp = (xmlEntityPtr) cur;
4457
switch (tmp->etype) {
4458
case XML_INTERNAL_GENERAL_ENTITY:
4459
case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4460
case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4461
q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4462
break;
4463
case XML_INTERNAL_PARAMETER_ENTITY:
4464
case XML_EXTERNAL_PARAMETER_ENTITY:
4465
q = (xmlNodePtr)
4466
xmlGetParameterEntityFromDtd(ret, tmp->name);
4467
break;
4468
case XML_INTERNAL_PREDEFINED_ENTITY:
4469
break;
4470
}
4471
} else if (cur->type == XML_ELEMENT_DECL) {
4472
xmlElementPtr tmp = (xmlElementPtr) cur;
4473
q = (xmlNodePtr)
4474
xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4475
} else if (cur->type == XML_ATTRIBUTE_DECL) {
4476
xmlAttributePtr tmp = (xmlAttributePtr) cur;
4477
q = (xmlNodePtr)
4478
xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4479
} else if (cur->type == XML_COMMENT_NODE) {
4480
q = xmlCopyNode(cur, 0);
4481
}
4482
4483
if (q == NULL) {
4484
cur = cur->next;
4485
continue;
4486
}
4487
4488
if (p == NULL)
4489
ret->children = q;
4490
else
4491
p->next = q;
4492
4493
q->prev = p;
4494
q->parent = (xmlNodePtr) ret;
4495
q->next = NULL;
4496
ret->last = q;
4497
p = q;
4498
cur = cur->next;
4499
}
4500
4501
return(ret);
4502
}
4503
#endif
4504
4505
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4506
/**
4507
* xmlCopyDoc:
4508
* @doc: the document
4509
* @recursive: if not zero do a recursive copy.
4510
*
4511
* Do a copy of the document info. If recursive, the content tree will
4512
* be copied too as well as DTD, namespaces and entities.
4513
*
4514
* Returns: a new #xmlDocPtr, or NULL in case of error.
4515
*/
4516
xmlDocPtr
4517
xmlCopyDoc(xmlDocPtr doc, int recursive) {
4518
xmlDocPtr ret;
4519
4520
if (doc == NULL) return(NULL);
4521
ret = xmlNewDoc(doc->version);
4522
if (ret == NULL) return(NULL);
4523
ret->type = doc->type;
4524
if (doc->name != NULL)
4525
ret->name = xmlMemStrdup(doc->name);
4526
if (doc->encoding != NULL)
4527
ret->encoding = xmlStrdup(doc->encoding);
4528
if (doc->URL != NULL)
4529
ret->URL = xmlStrdup(doc->URL);
4530
ret->charset = doc->charset;
4531
ret->compression = doc->compression;
4532
ret->standalone = doc->standalone;
4533
if (!recursive) return(ret);
4534
4535
ret->last = NULL;
4536
ret->children = NULL;
4537
#ifdef LIBXML_TREE_ENABLED
4538
if (doc->intSubset != NULL) {
4539
ret->intSubset = xmlCopyDtd(doc->intSubset);
4540
if (ret->intSubset == NULL) {
4541
xmlFreeDoc(ret);
4542
return(NULL);
4543
}
4544
xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4545
ret->intSubset->parent = ret;
4546
}
4547
#endif
4548
if (doc->oldNs != NULL)
4549
ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4550
if (doc->children != NULL) {
4551
xmlNodePtr tmp;
4552
4553
ret->children = xmlStaticCopyNodeList(doc->children, ret,
4554
(xmlNodePtr)ret);
4555
ret->last = NULL;
4556
tmp = ret->children;
4557
while (tmp != NULL) {
4558
if (tmp->next == NULL)
4559
ret->last = tmp;
4560
tmp = tmp->next;
4561
}
4562
}
4563
return(ret);
4564
}
4565
#endif /* LIBXML_TREE_ENABLED */
4566
4567
/************************************************************************
4568
* *
4569
* Content access functions *
4570
* *
4571
************************************************************************/
4572
4573
/**
4574
* xmlGetLineNoInternal:
4575
* @node: valid node
4576
* @depth: used to limit any risk of recursion
4577
*
4578
* Get line number of @node.
4579
* Try to override the limitation of lines being store in 16 bits ints
4580
*
4581
* Returns the line number if successful, -1 otherwise
4582
*/
4583
static long
4584
xmlGetLineNoInternal(const xmlNode *node, int depth)
4585
{
4586
long result = -1;
4587
4588
if (depth >= 5)
4589
return(-1);
4590
4591
if (!node)
4592
return result;
4593
if ((node->type == XML_ELEMENT_NODE) ||
4594
(node->type == XML_TEXT_NODE) ||
4595
(node->type == XML_COMMENT_NODE) ||
4596
(node->type == XML_PI_NODE)) {
4597
if (node->line == 65535) {
4598
if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4599
result = (long) (ptrdiff_t) node->psvi;
4600
else if ((node->type == XML_ELEMENT_NODE) &&
4601
(node->children != NULL))
4602
result = xmlGetLineNoInternal(node->children, depth + 1);
4603
else if (node->next != NULL)
4604
result = xmlGetLineNoInternal(node->next, depth + 1);
4605
else if (node->prev != NULL)
4606
result = xmlGetLineNoInternal(node->prev, depth + 1);
4607
}
4608
if ((result == -1) || (result == 65535))
4609
result = (long) node->line;
4610
} else if ((node->prev != NULL) &&
4611
((node->prev->type == XML_ELEMENT_NODE) ||
4612
(node->prev->type == XML_TEXT_NODE) ||
4613
(node->prev->type == XML_COMMENT_NODE) ||
4614
(node->prev->type == XML_PI_NODE)))
4615
result = xmlGetLineNoInternal(node->prev, depth + 1);
4616
else if ((node->parent != NULL) &&
4617
(node->parent->type == XML_ELEMENT_NODE))
4618
result = xmlGetLineNoInternal(node->parent, depth + 1);
4619
4620
return result;
4621
}
4622
4623
/**
4624
* xmlGetLineNo:
4625
* @node: valid node
4626
*
4627
* Get line number of @node.
4628
* Try to override the limitation of lines being store in 16 bits ints
4629
* if XML_PARSE_BIG_LINES parser option was used
4630
*
4631
* Returns the line number if successful, -1 otherwise
4632
*/
4633
long
4634
xmlGetLineNo(const xmlNode *node)
4635
{
4636
return(xmlGetLineNoInternal(node, 0));
4637
}
4638
4639
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4640
/**
4641
* xmlGetNodePath:
4642
* @node: a node
4643
*
4644
* Build a structure based Path for the given node
4645
*
4646
* Returns the new path or NULL in case of error. The caller must free
4647
* the returned string
4648
*/
4649
xmlChar *
4650
xmlGetNodePath(const xmlNode *node)
4651
{
4652
const xmlNode *cur, *tmp, *next;
4653
xmlChar *buffer = NULL, *temp;
4654
size_t buf_len;
4655
xmlChar *buf;
4656
const char *sep;
4657
const char *name;
4658
char nametemp[100];
4659
int occur = 0, generic;
4660
4661
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4662
return (NULL);
4663
4664
buf_len = 500;
4665
buffer = (xmlChar *) xmlMallocAtomic(buf_len);
4666
if (buffer == NULL) {
4667
xmlTreeErrMemory("getting node path");
4668
return (NULL);
4669
}
4670
buf = (xmlChar *) xmlMallocAtomic(buf_len);
4671
if (buf == NULL) {
4672
xmlTreeErrMemory("getting node path");
4673
xmlFree(buffer);
4674
return (NULL);
4675
}
4676
4677
buffer[0] = 0;
4678
cur = node;
4679
do {
4680
name = "";
4681
sep = "?";
4682
occur = 0;
4683
if ((cur->type == XML_DOCUMENT_NODE) ||
4684
(cur->type == XML_HTML_DOCUMENT_NODE)) {
4685
if (buffer[0] == '/')
4686
break;
4687
sep = "/";
4688
next = NULL;
4689
} else if (cur->type == XML_ELEMENT_NODE) {
4690
generic = 0;
4691
sep = "/";
4692
name = (const char *) cur->name;
4693
if (cur->ns) {
4694
if (cur->ns->prefix != NULL) {
4695
snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4696
(char *)cur->ns->prefix, (char *)cur->name);
4697
nametemp[sizeof(nametemp) - 1] = 0;
4698
name = nametemp;
4699
} else {
4700
/*
4701
* We cannot express named elements in the default
4702
* namespace, so use "*".
4703
*/
4704
generic = 1;
4705
name = "*";
4706
}
4707
}
4708
next = cur->parent;
4709
4710
/*
4711
* Thumbler index computation
4712
* TODO: the occurrence test seems bogus for namespaced names
4713
*/
4714
tmp = cur->prev;
4715
while (tmp != NULL) {
4716
if ((tmp->type == XML_ELEMENT_NODE) &&
4717
(generic ||
4718
(xmlStrEqual(cur->name, tmp->name) &&
4719
((tmp->ns == cur->ns) ||
4720
((tmp->ns != NULL) && (cur->ns != NULL) &&
4721
(xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4722
occur++;
4723
tmp = tmp->prev;
4724
}
4725
if (occur == 0) {
4726
tmp = cur->next;
4727
while (tmp != NULL && occur == 0) {
4728
if ((tmp->type == XML_ELEMENT_NODE) &&
4729
(generic ||
4730
(xmlStrEqual(cur->name, tmp->name) &&
4731
((tmp->ns == cur->ns) ||
4732
((tmp->ns != NULL) && (cur->ns != NULL) &&
4733
(xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4734
occur++;
4735
tmp = tmp->next;
4736
}
4737
if (occur != 0)
4738
occur = 1;
4739
} else
4740
occur++;
4741
} else if (cur->type == XML_COMMENT_NODE) {
4742
sep = "/";
4743
name = "comment()";
4744
next = cur->parent;
4745
4746
/*
4747
* Thumbler index computation
4748
*/
4749
tmp = cur->prev;
4750
while (tmp != NULL) {
4751
if (tmp->type == XML_COMMENT_NODE)
4752
occur++;
4753
tmp = tmp->prev;
4754
}
4755
if (occur == 0) {
4756
tmp = cur->next;
4757
while (tmp != NULL && occur == 0) {
4758
if (tmp->type == XML_COMMENT_NODE)
4759
occur++;
4760
tmp = tmp->next;
4761
}
4762
if (occur != 0)
4763
occur = 1;
4764
} else
4765
occur++;
4766
} else if ((cur->type == XML_TEXT_NODE) ||
4767
(cur->type == XML_CDATA_SECTION_NODE)) {
4768
sep = "/";
4769
name = "text()";
4770
next = cur->parent;
4771
4772
/*
4773
* Thumbler index computation
4774
*/
4775
tmp = cur->prev;
4776
while (tmp != NULL) {
4777
if ((tmp->type == XML_TEXT_NODE) ||
4778
(tmp->type == XML_CDATA_SECTION_NODE))
4779
occur++;
4780
tmp = tmp->prev;
4781
}
4782
/*
4783
* Evaluate if this is the only text- or CDATA-section-node;
4784
* if yes, then we'll get "text()", otherwise "text()[1]".
4785
*/
4786
if (occur == 0) {
4787
tmp = cur->next;
4788
while (tmp != NULL) {
4789
if ((tmp->type == XML_TEXT_NODE) ||
4790
(tmp->type == XML_CDATA_SECTION_NODE))
4791
{
4792
occur = 1;
4793
break;
4794
}
4795
tmp = tmp->next;
4796
}
4797
} else
4798
occur++;
4799
} else if (cur->type == XML_PI_NODE) {
4800
sep = "/";
4801
snprintf(nametemp, sizeof(nametemp) - 1,
4802
"processing-instruction('%s')", (char *)cur->name);
4803
nametemp[sizeof(nametemp) - 1] = 0;
4804
name = nametemp;
4805
4806
next = cur->parent;
4807
4808
/*
4809
* Thumbler index computation
4810
*/
4811
tmp = cur->prev;
4812
while (tmp != NULL) {
4813
if ((tmp->type == XML_PI_NODE) &&
4814
(xmlStrEqual(cur->name, tmp->name)))
4815
occur++;
4816
tmp = tmp->prev;
4817
}
4818
if (occur == 0) {
4819
tmp = cur->next;
4820
while (tmp != NULL && occur == 0) {
4821
if ((tmp->type == XML_PI_NODE) &&
4822
(xmlStrEqual(cur->name, tmp->name)))
4823
occur++;
4824
tmp = tmp->next;
4825
}
4826
if (occur != 0)
4827
occur = 1;
4828
} else
4829
occur++;
4830
4831
} else if (cur->type == XML_ATTRIBUTE_NODE) {
4832
sep = "/@";
4833
name = (const char *) (((xmlAttrPtr) cur)->name);
4834
if (cur->ns) {
4835
if (cur->ns->prefix != NULL)
4836
snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4837
(char *)cur->ns->prefix, (char *)cur->name);
4838
else
4839
snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4840
(char *)cur->name);
4841
nametemp[sizeof(nametemp) - 1] = 0;
4842
name = nametemp;
4843
}
4844
next = ((xmlAttrPtr) cur)->parent;
4845
} else {
4846
xmlFree(buf);
4847
xmlFree(buffer);
4848
return (NULL);
4849
}
4850
4851
/*
4852
* Make sure there is enough room
4853
*/
4854
if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4855
buf_len =
4856
2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4857
temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4858
if (temp == NULL) {
4859
xmlTreeErrMemory("getting node path");
4860
xmlFree(buf);
4861
xmlFree(buffer);
4862
return (NULL);
4863
}
4864
buffer = temp;
4865
temp = (xmlChar *) xmlRealloc(buf, buf_len);
4866
if (temp == NULL) {
4867
xmlTreeErrMemory("getting node path");
4868
xmlFree(buf);
4869
xmlFree(buffer);
4870
return (NULL);
4871
}
4872
buf = temp;
4873
}
4874
if (occur == 0)
4875
snprintf((char *) buf, buf_len, "%s%s%s",
4876
sep, name, (char *) buffer);
4877
else
4878
snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4879
sep, name, occur, (char *) buffer);
4880
snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4881
cur = next;
4882
} while (cur != NULL);
4883
xmlFree(buf);
4884
return (buffer);
4885
}
4886
#endif /* LIBXML_TREE_ENABLED */
4887
4888
/**
4889
* xmlDocGetRootElement:
4890
* @doc: the document
4891
*
4892
* Get the root element of the document (doc->children is a list
4893
* containing possibly comments, PIs, etc ...).
4894
*
4895
* Returns the #xmlNodePtr for the root or NULL
4896
*/
4897
xmlNodePtr
4898
xmlDocGetRootElement(const xmlDoc *doc) {
4899
xmlNodePtr ret;
4900
4901
if (doc == NULL) return(NULL);
4902
ret = doc->children;
4903
while (ret != NULL) {
4904
if (ret->type == XML_ELEMENT_NODE)
4905
return(ret);
4906
ret = ret->next;
4907
}
4908
return(ret);
4909
}
4910
4911
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4912
/**
4913
* xmlDocSetRootElement:
4914
* @doc: the document
4915
* @root: the new document root element, if root is NULL no action is taken,
4916
* to remove a node from a document use xmlUnlinkNode(root) instead.
4917
*
4918
* Set the root element of the document (doc->children is a list
4919
* containing possibly comments, PIs, etc ...).
4920
*
4921
* Returns the old root element if any was found, NULL if root was NULL
4922
*/
4923
xmlNodePtr
4924
xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4925
xmlNodePtr old = NULL;
4926
4927
if (doc == NULL) return(NULL);
4928
if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
4929
return(NULL);
4930
xmlUnlinkNode(root);
4931
xmlSetTreeDoc(root, doc);
4932
root->parent = (xmlNodePtr) doc;
4933
old = doc->children;
4934
while (old != NULL) {
4935
if (old->type == XML_ELEMENT_NODE)
4936
break;
4937
old = old->next;
4938
}
4939
if (old == NULL) {
4940
if (doc->children == NULL) {
4941
doc->children = root;
4942
doc->last = root;
4943
} else {
4944
xmlAddSibling(doc->children, root);
4945
}
4946
} else {
4947
xmlReplaceNode(old, root);
4948
}
4949
return(old);
4950
}
4951
#endif
4952
4953
#if defined(LIBXML_TREE_ENABLED)
4954
/**
4955
* xmlNodeSetLang:
4956
* @cur: the node being changed
4957
* @lang: the language description
4958
*
4959
* Set the language of a node, i.e. the values of the xml:lang
4960
* attribute.
4961
*/
4962
void
4963
xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
4964
xmlNsPtr ns;
4965
4966
if (cur == NULL) return;
4967
switch(cur->type) {
4968
case XML_TEXT_NODE:
4969
case XML_CDATA_SECTION_NODE:
4970
case XML_COMMENT_NODE:
4971
case XML_DOCUMENT_NODE:
4972
case XML_DOCUMENT_TYPE_NODE:
4973
case XML_DOCUMENT_FRAG_NODE:
4974
case XML_NOTATION_NODE:
4975
case XML_HTML_DOCUMENT_NODE:
4976
case XML_DTD_NODE:
4977
case XML_ELEMENT_DECL:
4978
case XML_ATTRIBUTE_DECL:
4979
case XML_ENTITY_DECL:
4980
case XML_PI_NODE:
4981
case XML_ENTITY_REF_NODE:
4982
case XML_ENTITY_NODE:
4983
case XML_NAMESPACE_DECL:
4984
case XML_XINCLUDE_START:
4985
case XML_XINCLUDE_END:
4986
return;
4987
case XML_ELEMENT_NODE:
4988
case XML_ATTRIBUTE_NODE:
4989
break;
4990
}
4991
ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4992
if (ns == NULL)
4993
return;
4994
xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
4995
}
4996
#endif /* LIBXML_TREE_ENABLED */
4997
4998
/**
4999
* xmlNodeGetLang:
5000
* @cur: the node being checked
5001
*
5002
* Searches the language of a node, i.e. the values of the xml:lang
5003
* attribute or the one carried by the nearest ancestor.
5004
*
5005
* Returns a pointer to the lang value, or NULL if not found
5006
* It's up to the caller to free the memory with xmlFree().
5007
*/
5008
xmlChar *
5009
xmlNodeGetLang(const xmlNode *cur) {
5010
xmlChar *lang;
5011
5012
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
5013
return(NULL);
5014
while (cur != NULL) {
5015
lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
5016
if (lang != NULL)
5017
return(lang);
5018
cur = cur->parent;
5019
}
5020
return(NULL);
5021
}
5022
5023
5024
#ifdef LIBXML_TREE_ENABLED
5025
/**
5026
* xmlNodeSetSpacePreserve:
5027
* @cur: the node being changed
5028
* @val: the xml:space value ("0": default, 1: "preserve")
5029
*
5030
* Set (or reset) the space preserving behaviour of a node, i.e. the
5031
* value of the xml:space attribute.
5032
*/
5033
void
5034
xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
5035
xmlNsPtr ns;
5036
5037
if (cur == NULL) return;
5038
switch(cur->type) {
5039
case XML_TEXT_NODE:
5040
case XML_CDATA_SECTION_NODE:
5041
case XML_COMMENT_NODE:
5042
case XML_DOCUMENT_NODE:
5043
case XML_DOCUMENT_TYPE_NODE:
5044
case XML_DOCUMENT_FRAG_NODE:
5045
case XML_NOTATION_NODE:
5046
case XML_HTML_DOCUMENT_NODE:
5047
case XML_DTD_NODE:
5048
case XML_ELEMENT_DECL:
5049
case XML_ATTRIBUTE_DECL:
5050
case XML_ENTITY_DECL:
5051
case XML_PI_NODE:
5052
case XML_ENTITY_REF_NODE:
5053
case XML_ENTITY_NODE:
5054
case XML_NAMESPACE_DECL:
5055
case XML_XINCLUDE_START:
5056
case XML_XINCLUDE_END:
5057
return;
5058
case XML_ELEMENT_NODE:
5059
case XML_ATTRIBUTE_NODE:
5060
break;
5061
}
5062
ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5063
if (ns == NULL)
5064
return;
5065
switch (val) {
5066
case 0:
5067
xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
5068
break;
5069
case 1:
5070
xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
5071
break;
5072
}
5073
}
5074
#endif /* LIBXML_TREE_ENABLED */
5075
5076
/**
5077
* xmlNodeGetSpacePreserve:
5078
* @cur: the node being checked
5079
*
5080
* Searches the space preserving behaviour of a node, i.e. the values
5081
* of the xml:space attribute or the one carried by the nearest
5082
* ancestor.
5083
*
5084
* Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
5085
*/
5086
int
5087
xmlNodeGetSpacePreserve(const xmlNode *cur) {
5088
xmlChar *space;
5089
5090
if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5091
return(-1);
5092
while (cur != NULL) {
5093
space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
5094
if (space != NULL) {
5095
if (xmlStrEqual(space, BAD_CAST "preserve")) {
5096
xmlFree(space);
5097
return(1);
5098
}
5099
if (xmlStrEqual(space, BAD_CAST "default")) {
5100
xmlFree(space);
5101
return(0);
5102
}
5103
xmlFree(space);
5104
}
5105
cur = cur->parent;
5106
}
5107
return(-1);
5108
}
5109
5110
#ifdef LIBXML_TREE_ENABLED
5111
/**
5112
* xmlNodeSetName:
5113
* @cur: the node being changed
5114
* @name: the new tag name
5115
*
5116
* Set (or reset) the name of a node.
5117
*/
5118
void
5119
xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
5120
xmlDocPtr doc;
5121
xmlDictPtr dict;
5122
const xmlChar *freeme = NULL;
5123
5124
if (cur == NULL) return;
5125
if (name == NULL) return;
5126
switch(cur->type) {
5127
case XML_TEXT_NODE:
5128
case XML_CDATA_SECTION_NODE:
5129
case XML_COMMENT_NODE:
5130
case XML_DOCUMENT_TYPE_NODE:
5131
case XML_DOCUMENT_FRAG_NODE:
5132
case XML_NOTATION_NODE:
5133
case XML_HTML_DOCUMENT_NODE:
5134
case XML_NAMESPACE_DECL:
5135
case XML_XINCLUDE_START:
5136
case XML_XINCLUDE_END:
5137
return;
5138
case XML_ELEMENT_NODE:
5139
case XML_ATTRIBUTE_NODE:
5140
case XML_PI_NODE:
5141
case XML_ENTITY_REF_NODE:
5142
case XML_ENTITY_NODE:
5143
case XML_DTD_NODE:
5144
case XML_DOCUMENT_NODE:
5145
case XML_ELEMENT_DECL:
5146
case XML_ATTRIBUTE_DECL:
5147
case XML_ENTITY_DECL:
5148
break;
5149
}
5150
doc = cur->doc;
5151
if (doc != NULL)
5152
dict = doc->dict;
5153
else
5154
dict = NULL;
5155
if (dict != NULL) {
5156
if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5157
freeme = cur->name;
5158
cur->name = xmlDictLookup(dict, name, -1);
5159
} else {
5160
if (cur->name != NULL)
5161
freeme = cur->name;
5162
cur->name = xmlStrdup(name);
5163
}
5164
5165
if (freeme)
5166
xmlFree((xmlChar *) freeme);
5167
}
5168
#endif
5169
5170
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
5171
/**
5172
* xmlNodeSetBase:
5173
* @cur: the node being changed
5174
* @uri: the new base URI
5175
*
5176
* Set (or reset) the base URI of a node, i.e. the value of the
5177
* xml:base attribute.
5178
*/
5179
void
5180
xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
5181
xmlNsPtr ns;
5182
xmlChar* fixed;
5183
5184
if (cur == NULL) return;
5185
switch(cur->type) {
5186
case XML_TEXT_NODE:
5187
case XML_CDATA_SECTION_NODE:
5188
case XML_COMMENT_NODE:
5189
case XML_DOCUMENT_TYPE_NODE:
5190
case XML_DOCUMENT_FRAG_NODE:
5191
case XML_NOTATION_NODE:
5192
case XML_DTD_NODE:
5193
case XML_ELEMENT_DECL:
5194
case XML_ATTRIBUTE_DECL:
5195
case XML_ENTITY_DECL:
5196
case XML_PI_NODE:
5197
case XML_ENTITY_REF_NODE:
5198
case XML_ENTITY_NODE:
5199
case XML_NAMESPACE_DECL:
5200
case XML_XINCLUDE_START:
5201
case XML_XINCLUDE_END:
5202
return;
5203
case XML_ELEMENT_NODE:
5204
case XML_ATTRIBUTE_NODE:
5205
break;
5206
case XML_DOCUMENT_NODE:
5207
case XML_HTML_DOCUMENT_NODE: {
5208
xmlDocPtr doc = (xmlDocPtr) cur;
5209
5210
if (doc->URL != NULL)
5211
xmlFree((xmlChar *) doc->URL);
5212
if (uri == NULL)
5213
doc->URL = NULL;
5214
else
5215
doc->URL = xmlPathToURI(uri);
5216
return;
5217
}
5218
}
5219
5220
ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5221
if (ns == NULL)
5222
return;
5223
fixed = xmlPathToURI(uri);
5224
if (fixed != NULL) {
5225
xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
5226
xmlFree(fixed);
5227
} else {
5228
xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5229
}
5230
}
5231
#endif /* LIBXML_TREE_ENABLED */
5232
5233
/**
5234
* xmlNodeGetBase:
5235
* @doc: the document the node pertains to
5236
* @cur: the node being checked
5237
*
5238
* Searches for the BASE URL. The code should work on both XML
5239
* and HTML document even if base mechanisms are completely different.
5240
* It returns the base as defined in RFC 2396 sections
5241
* 5.1.1. Base URI within Document Content
5242
* and
5243
* 5.1.2. Base URI from the Encapsulating Entity
5244
* However it does not return the document base (5.1.3), use
5245
* doc->URL in this case
5246
*
5247
* Returns a pointer to the base URL, or NULL if not found
5248
* It's up to the caller to free the memory with xmlFree().
5249
*/
5250
xmlChar *
5251
xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) {
5252
xmlChar *oldbase = NULL;
5253
xmlChar *base, *newbase;
5254
5255
if ((cur == NULL) && (doc == NULL))
5256
return(NULL);
5257
if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
5258
return(NULL);
5259
if (doc == NULL) doc = cur->doc;
5260
if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5261
cur = doc->children;
5262
while ((cur != NULL) && (cur->name != NULL)) {
5263
if (cur->type != XML_ELEMENT_NODE) {
5264
cur = cur->next;
5265
continue;
5266
}
5267
if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5268
cur = cur->children;
5269
continue;
5270
}
5271
if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5272
cur = cur->children;
5273
continue;
5274
}
5275
if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5276
return(xmlGetProp(cur, BAD_CAST "href"));
5277
}
5278
cur = cur->next;
5279
}
5280
return(NULL);
5281
}
5282
while (cur != NULL) {
5283
if (cur->type == XML_ENTITY_DECL) {
5284
xmlEntityPtr ent = (xmlEntityPtr) cur;
5285
return(xmlStrdup(ent->URI));
5286
}
5287
if (cur->type == XML_ELEMENT_NODE) {
5288
base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
5289
if (base != NULL) {
5290
if (oldbase != NULL) {
5291
newbase = xmlBuildURI(oldbase, base);
5292
if (newbase != NULL) {
5293
xmlFree(oldbase);
5294
xmlFree(base);
5295
oldbase = newbase;
5296
} else {
5297
xmlFree(oldbase);
5298
xmlFree(base);
5299
return(NULL);
5300
}
5301
} else {
5302
oldbase = base;
5303
}
5304
if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5305
(!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5306
(!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5307
return(oldbase);
5308
}
5309
}
5310
cur = cur->parent;
5311
}
5312
if ((doc != NULL) && (doc->URL != NULL)) {
5313
if (oldbase == NULL)
5314
return(xmlStrdup(doc->URL));
5315
newbase = xmlBuildURI(oldbase, doc->URL);
5316
xmlFree(oldbase);
5317
return(newbase);
5318
}
5319
return(oldbase);
5320
}
5321
5322
/**
5323
* xmlNodeBufGetContent:
5324
* @buffer: a buffer
5325
* @cur: the node being read
5326
*
5327
* Read the value of a node @cur, this can be either the text carried
5328
* directly by this node if it's a TEXT node or the aggregate string
5329
* of the values carried by this node child's (TEXT and ENTITY_REF).
5330
* Entity references are substituted.
5331
* Fills up the buffer @buffer with this value
5332
*
5333
* Returns 0 in case of success and -1 in case of error.
5334
*/
5335
int
5336
xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur)
5337
{
5338
xmlBufPtr buf;
5339
int ret;
5340
5341
if ((cur == NULL) || (buffer == NULL)) return(-1);
5342
buf = xmlBufFromBuffer(buffer);
5343
ret = xmlBufGetNodeContent(buf, cur);
5344
buffer = xmlBufBackToBuffer(buf);
5345
if ((ret < 0) || (buffer == NULL))
5346
return(-1);
5347
return(0);
5348
}
5349
5350
/**
5351
* xmlBufGetNodeContent:
5352
* @buf: a buffer xmlBufPtr
5353
* @cur: the node being read
5354
*
5355
* Read the value of a node @cur, this can be either the text carried
5356
* directly by this node if it's a TEXT node or the aggregate string
5357
* of the values carried by this node child's (TEXT and ENTITY_REF).
5358
* Entity references are substituted.
5359
* Fills up the buffer @buf with this value
5360
*
5361
* Returns 0 in case of success and -1 in case of error.
5362
*/
5363
int
5364
xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur)
5365
{
5366
if ((cur == NULL) || (buf == NULL)) return(-1);
5367
switch (cur->type) {
5368
case XML_CDATA_SECTION_NODE:
5369
case XML_TEXT_NODE:
5370
xmlBufCat(buf, cur->content);
5371
break;
5372
case XML_DOCUMENT_FRAG_NODE:
5373
case XML_ELEMENT_NODE:{
5374
const xmlNode *tmp = cur;
5375
5376
while (tmp != NULL) {
5377
switch (tmp->type) {
5378
case XML_CDATA_SECTION_NODE:
5379
case XML_TEXT_NODE:
5380
if (tmp->content != NULL)
5381
xmlBufCat(buf, tmp->content);
5382
break;
5383
case XML_ENTITY_REF_NODE:
5384
xmlBufGetNodeContent(buf, tmp);
5385
break;
5386
default:
5387
break;
5388
}
5389
/*
5390
* Skip to next node
5391
*/
5392
if (tmp->children != NULL) {
5393
if (tmp->children->type != XML_ENTITY_DECL) {
5394
tmp = tmp->children;
5395
continue;
5396
}
5397
}
5398
if (tmp == cur)
5399
break;
5400
5401
if (tmp->next != NULL) {
5402
tmp = tmp->next;
5403
continue;
5404
}
5405
5406
do {
5407
tmp = tmp->parent;
5408
if (tmp == NULL)
5409
break;
5410
if (tmp == cur) {
5411
tmp = NULL;
5412
break;
5413
}
5414
if (tmp->next != NULL) {
5415
tmp = tmp->next;
5416
break;
5417
}
5418
} while (tmp != NULL);
5419
}
5420
break;
5421
}
5422
case XML_ATTRIBUTE_NODE:{
5423
xmlAttrPtr attr = (xmlAttrPtr) cur;
5424
xmlNodePtr tmp = attr->children;
5425
5426
while (tmp != NULL) {
5427
if (tmp->type == XML_TEXT_NODE)
5428
xmlBufCat(buf, tmp->content);
5429
else
5430
xmlBufGetNodeContent(buf, tmp);
5431
tmp = tmp->next;
5432
}
5433
break;
5434
}
5435
case XML_COMMENT_NODE:
5436
case XML_PI_NODE:
5437
xmlBufCat(buf, cur->content);
5438
break;
5439
case XML_ENTITY_REF_NODE:{
5440
xmlEntityPtr ent;
5441
xmlNodePtr tmp;
5442
5443
/* lookup entity declaration */
5444
ent = xmlGetDocEntity(cur->doc, cur->name);
5445
if (ent == NULL)
5446
return(-1);
5447
5448
/* an entity content can be any "well balanced chunk",
5449
* i.e. the result of the content [43] production:
5450
* http://www.w3.org/TR/REC-xml#NT-content
5451
* -> we iterate through child nodes and recursive call
5452
* xmlNodeGetContent() which handles all possible node types */
5453
tmp = ent->children;
5454
while (tmp) {
5455
xmlBufGetNodeContent(buf, tmp);
5456
tmp = tmp->next;
5457
}
5458
break;
5459
}
5460
case XML_ENTITY_NODE:
5461
case XML_DOCUMENT_TYPE_NODE:
5462
case XML_NOTATION_NODE:
5463
case XML_DTD_NODE:
5464
case XML_XINCLUDE_START:
5465
case XML_XINCLUDE_END:
5466
break;
5467
case XML_DOCUMENT_NODE:
5468
case XML_HTML_DOCUMENT_NODE:
5469
cur = cur->children;
5470
while (cur!= NULL) {
5471
if ((cur->type == XML_ELEMENT_NODE) ||
5472
(cur->type == XML_TEXT_NODE) ||
5473
(cur->type == XML_CDATA_SECTION_NODE)) {
5474
xmlBufGetNodeContent(buf, cur);
5475
}
5476
cur = cur->next;
5477
}
5478
break;
5479
case XML_NAMESPACE_DECL:
5480
xmlBufCat(buf, ((xmlNsPtr) cur)->href);
5481
break;
5482
case XML_ELEMENT_DECL:
5483
case XML_ATTRIBUTE_DECL:
5484
case XML_ENTITY_DECL:
5485
break;
5486
}
5487
return(0);
5488
}
5489
5490
/**
5491
* xmlNodeGetContent:
5492
* @cur: the node being read
5493
*
5494
* Read the value of a node, this can be either the text carried
5495
* directly by this node if it's a TEXT node or the aggregate string
5496
* of the values carried by this node child's (TEXT and ENTITY_REF).
5497
* Entity references are substituted.
5498
* Returns a new #xmlChar * or NULL if no content is available.
5499
* It's up to the caller to free the memory with xmlFree().
5500
*/
5501
xmlChar *
5502
xmlNodeGetContent(const xmlNode *cur)
5503
{
5504
if (cur == NULL)
5505
return (NULL);
5506
switch (cur->type) {
5507
case XML_DOCUMENT_FRAG_NODE:
5508
case XML_ELEMENT_NODE:{
5509
xmlBufPtr buf;
5510
xmlChar *ret;
5511
5512
buf = xmlBufCreateSize(64);
5513
if (buf == NULL)
5514
return (NULL);
5515
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
5516
xmlBufGetNodeContent(buf, cur);
5517
ret = xmlBufDetach(buf);
5518
xmlBufFree(buf);
5519
return (ret);
5520
}
5521
case XML_ATTRIBUTE_NODE:
5522
return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
5523
case XML_COMMENT_NODE:
5524
case XML_PI_NODE:
5525
if (cur->content != NULL)
5526
return (xmlStrdup(cur->content));
5527
return (NULL);
5528
case XML_ENTITY_REF_NODE:{
5529
xmlEntityPtr ent;
5530
xmlBufPtr buf;
5531
xmlChar *ret;
5532
5533
/* lookup entity declaration */
5534
ent = xmlGetDocEntity(cur->doc, cur->name);
5535
if (ent == NULL)
5536
return (NULL);
5537
5538
buf = xmlBufCreate();
5539
if (buf == NULL)
5540
return (NULL);
5541
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
5542
5543
xmlBufGetNodeContent(buf, cur);
5544
5545
ret = xmlBufDetach(buf);
5546
xmlBufFree(buf);
5547
return (ret);
5548
}
5549
case XML_ENTITY_NODE:
5550
case XML_DOCUMENT_TYPE_NODE:
5551
case XML_NOTATION_NODE:
5552
case XML_DTD_NODE:
5553
case XML_XINCLUDE_START:
5554
case XML_XINCLUDE_END:
5555
return (NULL);
5556
case XML_DOCUMENT_NODE:
5557
case XML_HTML_DOCUMENT_NODE: {
5558
xmlBufPtr buf;
5559
xmlChar *ret;
5560
5561
buf = xmlBufCreate();
5562
if (buf == NULL)
5563
return (NULL);
5564
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
5565
5566
xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
5567
5568
ret = xmlBufDetach(buf);
5569
xmlBufFree(buf);
5570
return (ret);
5571
}
5572
case XML_NAMESPACE_DECL: {
5573
xmlChar *tmp;
5574
5575
tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5576
return (tmp);
5577
}
5578
case XML_ELEMENT_DECL:
5579
/* TODO !!! */
5580
return (NULL);
5581
case XML_ATTRIBUTE_DECL:
5582
/* TODO !!! */
5583
return (NULL);
5584
case XML_ENTITY_DECL:
5585
/* TODO !!! */
5586
return (NULL);
5587
case XML_CDATA_SECTION_NODE:
5588
case XML_TEXT_NODE:
5589
if (cur->content != NULL)
5590
return (xmlStrdup(cur->content));
5591
return (NULL);
5592
}
5593
return (NULL);
5594
}
5595
5596
/**
5597
* xmlNodeSetContent:
5598
* @cur: the node being modified
5599
* @content: the new value of the content
5600
*
5601
* Replace the content of a node.
5602
* NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5603
* references, but XML special chars need to be escaped first by using
5604
* xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5605
*/
5606
void
5607
xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5608
if (cur == NULL) {
5609
return;
5610
}
5611
switch (cur->type) {
5612
case XML_DOCUMENT_FRAG_NODE:
5613
case XML_ELEMENT_NODE:
5614
case XML_ATTRIBUTE_NODE:
5615
if (cur->children != NULL) xmlFreeNodeList(cur->children);
5616
cur->children = xmlStringGetNodeList(cur->doc, content);
5617
UPDATE_LAST_CHILD_AND_PARENT(cur)
5618
break;
5619
case XML_TEXT_NODE:
5620
case XML_CDATA_SECTION_NODE:
5621
case XML_ENTITY_REF_NODE:
5622
case XML_ENTITY_NODE:
5623
case XML_PI_NODE:
5624
case XML_COMMENT_NODE:
5625
if ((cur->content != NULL) &&
5626
(cur->content != (xmlChar *) &(cur->properties))) {
5627
if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5628
(xmlDictOwns(cur->doc->dict, cur->content))))
5629
xmlFree(cur->content);
5630
}
5631
if (cur->children != NULL) xmlFreeNodeList(cur->children);
5632
cur->last = cur->children = NULL;
5633
if (content != NULL) {
5634
cur->content = xmlStrdup(content);
5635
} else
5636
cur->content = NULL;
5637
cur->properties = NULL;
5638
break;
5639
case XML_DOCUMENT_NODE:
5640
case XML_HTML_DOCUMENT_NODE:
5641
case XML_DOCUMENT_TYPE_NODE:
5642
case XML_XINCLUDE_START:
5643
case XML_XINCLUDE_END:
5644
break;
5645
case XML_NOTATION_NODE:
5646
break;
5647
case XML_DTD_NODE:
5648
break;
5649
case XML_NAMESPACE_DECL:
5650
break;
5651
case XML_ELEMENT_DECL:
5652
/* TODO !!! */
5653
break;
5654
case XML_ATTRIBUTE_DECL:
5655
/* TODO !!! */
5656
break;
5657
case XML_ENTITY_DECL:
5658
/* TODO !!! */
5659
break;
5660
}
5661
}
5662
5663
#ifdef LIBXML_TREE_ENABLED
5664
/**
5665
* xmlNodeSetContentLen:
5666
* @cur: the node being modified
5667
* @content: the new value of the content
5668
* @len: the size of @content
5669
*
5670
* Replace the content of a node.
5671
* NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5672
* references, but XML special chars need to be escaped first by using
5673
* xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5674
*/
5675
void
5676
xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5677
if (cur == NULL) {
5678
return;
5679
}
5680
switch (cur->type) {
5681
case XML_DOCUMENT_FRAG_NODE:
5682
case XML_ELEMENT_NODE:
5683
case XML_ATTRIBUTE_NODE:
5684
if (cur->children != NULL) xmlFreeNodeList(cur->children);
5685
cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5686
UPDATE_LAST_CHILD_AND_PARENT(cur)
5687
break;
5688
case XML_TEXT_NODE:
5689
case XML_CDATA_SECTION_NODE:
5690
case XML_ENTITY_REF_NODE:
5691
case XML_ENTITY_NODE:
5692
case XML_PI_NODE:
5693
case XML_COMMENT_NODE:
5694
case XML_NOTATION_NODE:
5695
if ((cur->content != NULL) &&
5696
(cur->content != (xmlChar *) &(cur->properties))) {
5697
if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5698
(xmlDictOwns(cur->doc->dict, cur->content))))
5699
xmlFree(cur->content);
5700
}
5701
if (cur->children != NULL) xmlFreeNodeList(cur->children);
5702
cur->children = cur->last = NULL;
5703
if (content != NULL) {
5704
cur->content = xmlStrndup(content, len);
5705
} else
5706
cur->content = NULL;
5707
cur->properties = NULL;
5708
break;
5709
case XML_DOCUMENT_NODE:
5710
case XML_DTD_NODE:
5711
case XML_HTML_DOCUMENT_NODE:
5712
case XML_DOCUMENT_TYPE_NODE:
5713
case XML_NAMESPACE_DECL:
5714
case XML_XINCLUDE_START:
5715
case XML_XINCLUDE_END:
5716
break;
5717
case XML_ELEMENT_DECL:
5718
/* TODO !!! */
5719
break;
5720
case XML_ATTRIBUTE_DECL:
5721
/* TODO !!! */
5722
break;
5723
case XML_ENTITY_DECL:
5724
/* TODO !!! */
5725
break;
5726
}
5727
}
5728
#endif /* LIBXML_TREE_ENABLED */
5729
5730
/**
5731
* xmlNodeAddContentLen:
5732
* @cur: the node being modified
5733
* @content: extra content
5734
* @len: the size of @content
5735
*
5736
* Append the extra substring to the node content.
5737
* NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5738
* raw text, so unescaped XML special chars are allowed, entity
5739
* references are not supported.
5740
*/
5741
void
5742
xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5743
if (cur == NULL) {
5744
return;
5745
}
5746
if (len <= 0) return;
5747
switch (cur->type) {
5748
case XML_DOCUMENT_FRAG_NODE:
5749
case XML_ELEMENT_NODE: {
5750
xmlNodePtr last, newNode, tmp;
5751
5752
last = cur->last;
5753
newNode = xmlNewDocTextLen(cur->doc, content, len);
5754
if (newNode != NULL) {
5755
tmp = xmlAddChild(cur, newNode);
5756
if (tmp != newNode)
5757
return;
5758
if ((last != NULL) && (last->next == newNode)) {
5759
xmlTextMerge(last, newNode);
5760
}
5761
}
5762
break;
5763
}
5764
case XML_ATTRIBUTE_NODE:
5765
break;
5766
case XML_TEXT_NODE:
5767
case XML_CDATA_SECTION_NODE:
5768
case XML_ENTITY_REF_NODE:
5769
case XML_ENTITY_NODE:
5770
case XML_PI_NODE:
5771
case XML_COMMENT_NODE:
5772
case XML_NOTATION_NODE:
5773
if (content != NULL) {
5774
if ((cur->content == (xmlChar *) &(cur->properties)) ||
5775
((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5776
xmlDictOwns(cur->doc->dict, cur->content))) {
5777
cur->content = xmlStrncatNew(cur->content, content, len);
5778
cur->properties = NULL;
5779
} else {
5780
cur->content = xmlStrncat(cur->content, content, len);
5781
}
5782
}
5783
break;
5784
case XML_DOCUMENT_NODE:
5785
case XML_DTD_NODE:
5786
case XML_HTML_DOCUMENT_NODE:
5787
case XML_DOCUMENT_TYPE_NODE:
5788
case XML_NAMESPACE_DECL:
5789
case XML_XINCLUDE_START:
5790
case XML_XINCLUDE_END:
5791
break;
5792
case XML_ELEMENT_DECL:
5793
case XML_ATTRIBUTE_DECL:
5794
case XML_ENTITY_DECL:
5795
break;
5796
}
5797
}
5798
5799
/**
5800
* xmlNodeAddContent:
5801
* @cur: the node being modified
5802
* @content: extra content
5803
*
5804
* Append the extra substring to the node content.
5805
* NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5806
* raw text, so unescaped XML special chars are allowed, entity
5807
* references are not supported.
5808
*/
5809
void
5810
xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5811
int len;
5812
5813
if (cur == NULL) {
5814
return;
5815
}
5816
if (content == NULL) return;
5817
len = xmlStrlen(content);
5818
xmlNodeAddContentLen(cur, content, len);
5819
}
5820
5821
/**
5822
* xmlTextMerge:
5823
* @first: the first text node
5824
* @second: the second text node being merged
5825
*
5826
* Merge two text nodes into one
5827
* Returns the first text node augmented
5828
*/
5829
xmlNodePtr
5830
xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5831
if (first == NULL) return(second);
5832
if (second == NULL) return(first);
5833
if (first->type != XML_TEXT_NODE) return(first);
5834
if (second->type != XML_TEXT_NODE) return(first);
5835
if (second->name != first->name)
5836
return(first);
5837
xmlNodeAddContent(first, second->content);
5838
xmlUnlinkNode(second);
5839
xmlFreeNode(second);
5840
return(first);
5841
}
5842
5843
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
5844
/**
5845
* xmlGetNsList:
5846
* @doc: the document
5847
* @node: the current node
5848
*
5849
* Search all the namespace applying to a given element.
5850
* Returns an NULL terminated array of all the #xmlNsPtr found
5851
* that need to be freed by the caller or NULL if no
5852
* namespace if defined
5853
*/
5854
xmlNsPtr *
5855
xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node)
5856
{
5857
xmlNsPtr cur;
5858
xmlNsPtr *ret = NULL;
5859
int nbns = 0;
5860
int maxns = 0;
5861
int i;
5862
5863
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
5864
return(NULL);
5865
5866
while (node != NULL) {
5867
if (node->type == XML_ELEMENT_NODE) {
5868
cur = node->nsDef;
5869
while (cur != NULL) {
5870
for (i = 0; i < nbns; i++) {
5871
if ((cur->prefix == ret[i]->prefix) ||
5872
(xmlStrEqual(cur->prefix, ret[i]->prefix)))
5873
break;
5874
}
5875
if (i >= nbns) {
5876
if (nbns >= maxns) {
5877
xmlNsPtr *tmp;
5878
5879
maxns = maxns ? maxns * 2 : 10;
5880
tmp = (xmlNsPtr *) xmlRealloc(ret,
5881
(maxns + 1) *
5882
sizeof(xmlNsPtr));
5883
if (tmp == NULL) {
5884
xmlTreeErrMemory("getting namespace list");
5885
xmlFree(ret);
5886
return (NULL);
5887
}
5888
ret = tmp;
5889
}
5890
ret[nbns++] = cur;
5891
ret[nbns] = NULL;
5892
}
5893
5894
cur = cur->next;
5895
}
5896
}
5897
node = node->parent;
5898
}
5899
return (ret);
5900
}
5901
#endif /* LIBXML_TREE_ENABLED */
5902
5903
/*
5904
* xmlTreeEnsureXMLDecl:
5905
* @doc: the doc
5906
*
5907
* Ensures that there is an XML namespace declaration on the doc.
5908
*
5909
* Returns the XML ns-struct or NULL on API and internal errors.
5910
*/
5911
static xmlNsPtr
5912
xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5913
{
5914
if (doc == NULL)
5915
return (NULL);
5916
if (doc->oldNs != NULL)
5917
return (doc->oldNs);
5918
{
5919
xmlNsPtr ns;
5920
ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5921
if (ns == NULL) {
5922
xmlTreeErrMemory(
5923
"allocating the XML namespace");
5924
return (NULL);
5925
}
5926
memset(ns, 0, sizeof(xmlNs));
5927
ns->type = XML_LOCAL_NAMESPACE;
5928
ns->href = xmlStrdup(XML_XML_NAMESPACE);
5929
ns->prefix = xmlStrdup((const xmlChar *)"xml");
5930
doc->oldNs = ns;
5931
return (ns);
5932
}
5933
}
5934
5935
/**
5936
* xmlSearchNs:
5937
* @doc: the document
5938
* @node: the current node
5939
* @nameSpace: the namespace prefix
5940
*
5941
* Search a Ns registered under a given name space for a document.
5942
* recurse on the parents until it finds the defined namespace
5943
* or return NULL otherwise.
5944
* @nameSpace can be NULL, this is a search for the default namespace.
5945
* We don't allow to cross entities boundaries. If you don't declare
5946
* the namespace within those you will be in troubles !!! A warning
5947
* is generated to cover this case.
5948
*
5949
* Returns the namespace pointer or NULL.
5950
*/
5951
xmlNsPtr
5952
xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5953
5954
xmlNsPtr cur;
5955
const xmlNode *orig = node;
5956
5957
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
5958
if ((nameSpace != NULL) &&
5959
(xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
5960
if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5961
/*
5962
* The XML-1.0 namespace is normally held on the root
5963
* element. In this case exceptionally create it on the
5964
* node element.
5965
*/
5966
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5967
if (cur == NULL) {
5968
xmlTreeErrMemory("searching namespace");
5969
return(NULL);
5970
}
5971
memset(cur, 0, sizeof(xmlNs));
5972
cur->type = XML_LOCAL_NAMESPACE;
5973
cur->href = xmlStrdup(XML_XML_NAMESPACE);
5974
cur->prefix = xmlStrdup((const xmlChar *)"xml");
5975
cur->next = node->nsDef;
5976
node->nsDef = cur;
5977
return(cur);
5978
}
5979
if (doc == NULL) {
5980
doc = node->doc;
5981
if (doc == NULL)
5982
return(NULL);
5983
}
5984
/*
5985
* Return the XML namespace declaration held by the doc.
5986
*/
5987
if (doc->oldNs == NULL)
5988
return(xmlTreeEnsureXMLDecl(doc));
5989
else
5990
return(doc->oldNs);
5991
}
5992
while (node != NULL) {
5993
if ((node->type == XML_ENTITY_REF_NODE) ||
5994
(node->type == XML_ENTITY_NODE) ||
5995
(node->type == XML_ENTITY_DECL))
5996
return(NULL);
5997
if (node->type == XML_ELEMENT_NODE) {
5998
cur = node->nsDef;
5999
while (cur != NULL) {
6000
if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6001
(cur->href != NULL))
6002
return(cur);
6003
if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6004
(cur->href != NULL) &&
6005
(xmlStrEqual(cur->prefix, nameSpace)))
6006
return(cur);
6007
cur = cur->next;
6008
}
6009
if (orig != node) {
6010
cur = node->ns;
6011
if (cur != NULL) {
6012
if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6013
(cur->href != NULL))
6014
return(cur);
6015
if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6016
(cur->href != NULL) &&
6017
(xmlStrEqual(cur->prefix, nameSpace)))
6018
return(cur);
6019
}
6020
}
6021
}
6022
node = node->parent;
6023
}
6024
return(NULL);
6025
}
6026
6027
/**
6028
* xmlNsInScope:
6029
* @doc: the document
6030
* @node: the current node
6031
* @ancestor: the ancestor carrying the namespace
6032
* @prefix: the namespace prefix
6033
*
6034
* Verify that the given namespace held on @ancestor is still in scope
6035
* on node.
6036
*
6037
* Returns 1 if true, 0 if false and -1 in case of error.
6038
*/
6039
static int
6040
xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
6041
xmlNodePtr ancestor, const xmlChar * prefix)
6042
{
6043
xmlNsPtr tst;
6044
6045
while ((node != NULL) && (node != ancestor)) {
6046
if ((node->type == XML_ENTITY_REF_NODE) ||
6047
(node->type == XML_ENTITY_NODE) ||
6048
(node->type == XML_ENTITY_DECL))
6049
return (-1);
6050
if (node->type == XML_ELEMENT_NODE) {
6051
tst = node->nsDef;
6052
while (tst != NULL) {
6053
if ((tst->prefix == NULL)
6054
&& (prefix == NULL))
6055
return (0);
6056
if ((tst->prefix != NULL)
6057
&& (prefix != NULL)
6058
&& (xmlStrEqual(tst->prefix, prefix)))
6059
return (0);
6060
tst = tst->next;
6061
}
6062
}
6063
node = node->parent;
6064
}
6065
if (node != ancestor)
6066
return (-1);
6067
return (1);
6068
}
6069
6070
/**
6071
* xmlSearchNsByHref:
6072
* @doc: the document
6073
* @node: the current node
6074
* @href: the namespace value
6075
*
6076
* Search a Ns aliasing a given URI. Recurse on the parents until it finds
6077
* the defined namespace or return NULL otherwise.
6078
* Returns the namespace pointer or NULL.
6079
*/
6080
xmlNsPtr
6081
xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
6082
{
6083
xmlNsPtr cur;
6084
xmlNodePtr orig = node;
6085
int is_attr;
6086
6087
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL))
6088
return (NULL);
6089
if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
6090
/*
6091
* Only the document can hold the XML spec namespace.
6092
*/
6093
if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
6094
/*
6095
* The XML-1.0 namespace is normally held on the root
6096
* element. In this case exceptionally create it on the
6097
* node element.
6098
*/
6099
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6100
if (cur == NULL) {
6101
xmlTreeErrMemory("searching namespace");
6102
return (NULL);
6103
}
6104
memset(cur, 0, sizeof(xmlNs));
6105
cur->type = XML_LOCAL_NAMESPACE;
6106
cur->href = xmlStrdup(XML_XML_NAMESPACE);
6107
cur->prefix = xmlStrdup((const xmlChar *) "xml");
6108
cur->next = node->nsDef;
6109
node->nsDef = cur;
6110
return (cur);
6111
}
6112
if (doc == NULL) {
6113
doc = node->doc;
6114
if (doc == NULL)
6115
return(NULL);
6116
}
6117
/*
6118
* Return the XML namespace declaration held by the doc.
6119
*/
6120
if (doc->oldNs == NULL)
6121
return(xmlTreeEnsureXMLDecl(doc));
6122
else
6123
return(doc->oldNs);
6124
}
6125
is_attr = (node->type == XML_ATTRIBUTE_NODE);
6126
while (node != NULL) {
6127
if ((node->type == XML_ENTITY_REF_NODE) ||
6128
(node->type == XML_ENTITY_NODE) ||
6129
(node->type == XML_ENTITY_DECL))
6130
return (NULL);
6131
if (node->type == XML_ELEMENT_NODE) {
6132
cur = node->nsDef;
6133
while (cur != NULL) {
6134
if ((cur->href != NULL) && (href != NULL) &&
6135
(xmlStrEqual(cur->href, href))) {
6136
if (((!is_attr) || (cur->prefix != NULL)) &&
6137
(xmlNsInScope(doc, orig, node, cur->prefix) == 1))
6138
return (cur);
6139
}
6140
cur = cur->next;
6141
}
6142
if (orig != node) {
6143
cur = node->ns;
6144
if (cur != NULL) {
6145
if ((cur->href != NULL) && (href != NULL) &&
6146
(xmlStrEqual(cur->href, href))) {
6147
if (((!is_attr) || (cur->prefix != NULL)) &&
6148
(xmlNsInScope(doc, orig, node, cur->prefix) == 1))
6149
return (cur);
6150
}
6151
}
6152
}
6153
}
6154
node = node->parent;
6155
}
6156
return (NULL);
6157
}
6158
6159
/**
6160
* xmlNewReconciledNs:
6161
* @doc: the document
6162
* @tree: a node expected to hold the new namespace
6163
* @ns: the original namespace
6164
*
6165
* This function tries to locate a namespace definition in a tree
6166
* ancestors, or create a new namespace definition node similar to
6167
* @ns trying to reuse the same prefix. However if the given prefix is
6168
* null (default namespace) or reused within the subtree defined by
6169
* @tree or on one of its ancestors then a new prefix is generated.
6170
* Returns the (new) namespace definition or NULL in case of error
6171
*/
6172
static xmlNsPtr
6173
xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
6174
xmlNsPtr def;
6175
xmlChar prefix[50];
6176
int counter = 1;
6177
6178
if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) {
6179
return(NULL);
6180
}
6181
if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
6182
return(NULL);
6183
}
6184
/*
6185
* Search an existing namespace definition inherited.
6186
*/
6187
def = xmlSearchNsByHref(doc, tree, ns->href);
6188
if (def != NULL)
6189
return(def);
6190
6191
/*
6192
* Find a close prefix which is not already in use.
6193
* Let's strip namespace prefixes longer than 20 chars !
6194
*/
6195
if (ns->prefix == NULL)
6196
snprintf((char *) prefix, sizeof(prefix), "default");
6197
else
6198
snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
6199
6200
def = xmlSearchNs(doc, tree, prefix);
6201
while (def != NULL) {
6202
if (counter > 1000) return(NULL);
6203
if (ns->prefix == NULL)
6204
snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
6205
else
6206
snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
6207
(char *)ns->prefix, counter++);
6208
def = xmlSearchNs(doc, tree, prefix);
6209
}
6210
6211
/*
6212
* OK, now we are ready to create a new one.
6213
*/
6214
def = xmlNewNs(tree, ns->href, prefix);
6215
return(def);
6216
}
6217
6218
#ifdef LIBXML_TREE_ENABLED
6219
/**
6220
* xmlReconciliateNs:
6221
* @doc: the document
6222
* @tree: a node defining the subtree to reconciliate
6223
*
6224
* This function checks that all the namespaces declared within the given
6225
* tree are properly declared. This is needed for example after Copy or Cut
6226
* and then paste operations. The subtree may still hold pointers to
6227
* namespace declarations outside the subtree or invalid/masked. As much
6228
* as possible the function try to reuse the existing namespaces found in
6229
* the new environment. If not possible the new namespaces are redeclared
6230
* on @tree at the top of the given subtree.
6231
* Returns the number of namespace declarations created or -1 in case of error.
6232
*/
6233
int
6234
xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
6235
xmlNsPtr *oldNs = NULL;
6236
xmlNsPtr *newNs = NULL;
6237
int sizeCache = 0;
6238
int nbCache = 0;
6239
6240
xmlNsPtr n;
6241
xmlNodePtr node = tree;
6242
xmlAttrPtr attr;
6243
int ret = 0, i;
6244
6245
if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
6246
if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
6247
if (node->doc != doc) return(-1);
6248
while (node != NULL) {
6249
/*
6250
* Reconciliate the node namespace
6251
*/
6252
if (node->ns != NULL) {
6253
/*
6254
* initialize the cache if needed
6255
*/
6256
if (sizeCache == 0) {
6257
sizeCache = 10;
6258
oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6259
sizeof(xmlNsPtr));
6260
if (oldNs == NULL) {
6261
xmlTreeErrMemory("fixing namespaces");
6262
return(-1);
6263
}
6264
newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6265
sizeof(xmlNsPtr));
6266
if (newNs == NULL) {
6267
xmlTreeErrMemory("fixing namespaces");
6268
xmlFree(oldNs);
6269
return(-1);
6270
}
6271
}
6272
for (i = 0;i < nbCache;i++) {
6273
if (oldNs[i] == node->ns) {
6274
node->ns = newNs[i];
6275
break;
6276
}
6277
}
6278
if (i == nbCache) {
6279
/*
6280
* OK we need to recreate a new namespace definition
6281
*/
6282
n = xmlNewReconciledNs(doc, tree, node->ns);
6283
if (n != NULL) { /* :-( what if else ??? */
6284
/*
6285
* check if we need to grow the cache buffers.
6286
*/
6287
if (sizeCache <= nbCache) {
6288
sizeCache *= 2;
6289
oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
6290
sizeof(xmlNsPtr));
6291
if (oldNs == NULL) {
6292
xmlTreeErrMemory("fixing namespaces");
6293
xmlFree(newNs);
6294
return(-1);
6295
}
6296
newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
6297
sizeof(xmlNsPtr));
6298
if (newNs == NULL) {
6299
xmlTreeErrMemory("fixing namespaces");
6300
xmlFree(oldNs);
6301
return(-1);
6302
}
6303
}
6304
newNs[nbCache] = n;
6305
oldNs[nbCache++] = node->ns;
6306
node->ns = n;
6307
}
6308
}
6309
}
6310
/*
6311
* now check for namespace held by attributes on the node.
6312
*/
6313
if (node->type == XML_ELEMENT_NODE) {
6314
attr = node->properties;
6315
while (attr != NULL) {
6316
if (attr->ns != NULL) {
6317
/*
6318
* initialize the cache if needed
6319
*/
6320
if (sizeCache == 0) {
6321
sizeCache = 10;
6322
oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6323
sizeof(xmlNsPtr));
6324
if (oldNs == NULL) {
6325
xmlTreeErrMemory("fixing namespaces");
6326
return(-1);
6327
}
6328
newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6329
sizeof(xmlNsPtr));
6330
if (newNs == NULL) {
6331
xmlTreeErrMemory("fixing namespaces");
6332
xmlFree(oldNs);
6333
return(-1);
6334
}
6335
}
6336
for (i = 0;i < nbCache;i++) {
6337
if (oldNs[i] == attr->ns) {
6338
attr->ns = newNs[i];
6339
break;
6340
}
6341
}
6342
if (i == nbCache) {
6343
/*
6344
* OK we need to recreate a new namespace definition
6345
*/
6346
n = xmlNewReconciledNs(doc, tree, attr->ns);
6347
if (n != NULL) { /* :-( what if else ??? */
6348
/*
6349
* check if we need to grow the cache buffers.
6350
*/
6351
if (sizeCache <= nbCache) {
6352
sizeCache *= 2;
6353
oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
6354
sizeCache * sizeof(xmlNsPtr));
6355
if (oldNs == NULL) {
6356
xmlTreeErrMemory("fixing namespaces");
6357
xmlFree(newNs);
6358
return(-1);
6359
}
6360
newNs = (xmlNsPtr *) xmlRealloc(newNs,
6361
sizeCache * sizeof(xmlNsPtr));
6362
if (newNs == NULL) {
6363
xmlTreeErrMemory("fixing namespaces");
6364
xmlFree(oldNs);
6365
return(-1);
6366
}
6367
}
6368
newNs[nbCache] = n;
6369
oldNs[nbCache++] = attr->ns;
6370
attr->ns = n;
6371
}
6372
}
6373
}
6374
attr = attr->next;
6375
}
6376
}
6377
6378
/*
6379
* Browse the full subtree, deep first
6380
*/
6381
if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
6382
/* deep first */
6383
node = node->children;
6384
} else if ((node != tree) && (node->next != NULL)) {
6385
/* then siblings */
6386
node = node->next;
6387
} else if (node != tree) {
6388
/* go up to parents->next if needed */
6389
while (node != tree) {
6390
if (node->parent != NULL)
6391
node = node->parent;
6392
if ((node != tree) && (node->next != NULL)) {
6393
node = node->next;
6394
break;
6395
}
6396
if (node->parent == NULL) {
6397
node = NULL;
6398
break;
6399
}
6400
}
6401
/* exit condition */
6402
if (node == tree)
6403
node = NULL;
6404
} else
6405
break;
6406
}
6407
if (oldNs != NULL)
6408
xmlFree(oldNs);
6409
if (newNs != NULL)
6410
xmlFree(newNs);
6411
return(ret);
6412
}
6413
#endif /* LIBXML_TREE_ENABLED */
6414
6415
static xmlAttrPtr
6416
xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
6417
const xmlChar *nsName, int useDTD)
6418
{
6419
xmlAttrPtr prop;
6420
6421
/* Avoid unused variable warning if features are disabled. */
6422
(void) useDTD;
6423
6424
if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6425
return(NULL);
6426
6427
if (node->properties != NULL) {
6428
prop = node->properties;
6429
if (nsName == NULL) {
6430
/*
6431
* We want the attr to be in no namespace.
6432
*/
6433
do {
6434
if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6435
return(prop);
6436
}
6437
prop = prop->next;
6438
} while (prop != NULL);
6439
} else {
6440
/*
6441
* We want the attr to be in the specified namespace.
6442
*/
6443
do {
6444
if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6445
((prop->ns->href == nsName) ||
6446
xmlStrEqual(prop->ns->href, nsName)))
6447
{
6448
return(prop);
6449
}
6450
prop = prop->next;
6451
} while (prop != NULL);
6452
}
6453
}
6454
6455
#ifdef LIBXML_TREE_ENABLED
6456
if (! useDTD)
6457
return(NULL);
6458
/*
6459
* Check if there is a default/fixed attribute declaration in
6460
* the internal or external subset.
6461
*/
6462
if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6463
xmlDocPtr doc = node->doc;
6464
xmlAttributePtr attrDecl = NULL;
6465
xmlChar *elemQName, *tmpstr = NULL;
6466
6467
/*
6468
* We need the QName of the element for the DTD-lookup.
6469
*/
6470
if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6471
tmpstr = xmlStrdup(node->ns->prefix);
6472
tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6473
tmpstr = xmlStrcat(tmpstr, node->name);
6474
if (tmpstr == NULL)
6475
return(NULL);
6476
elemQName = tmpstr;
6477
} else
6478
elemQName = (xmlChar *) node->name;
6479
if (nsName == NULL) {
6480
/*
6481
* The common and nice case: Attr in no namespace.
6482
*/
6483
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6484
elemQName, name, NULL);
6485
if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6486
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6487
elemQName, name, NULL);
6488
}
6489
} else if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
6490
/*
6491
* The XML namespace must be bound to prefix 'xml'.
6492
*/
6493
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6494
elemQName, name, BAD_CAST "xml");
6495
if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6496
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6497
elemQName, name, BAD_CAST "xml");
6498
}
6499
} else {
6500
xmlNsPtr *nsList, *cur;
6501
6502
/*
6503
* The ugly case: Search using the prefixes of in-scope
6504
* ns-decls corresponding to @nsName.
6505
*/
6506
nsList = xmlGetNsList(node->doc, node);
6507
if (nsList == NULL) {
6508
if (tmpstr != NULL)
6509
xmlFree(tmpstr);
6510
return(NULL);
6511
}
6512
cur = nsList;
6513
while (*cur != NULL) {
6514
if (xmlStrEqual((*cur)->href, nsName)) {
6515
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6516
name, (*cur)->prefix);
6517
if (attrDecl)
6518
break;
6519
if (doc->extSubset != NULL) {
6520
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6521
name, (*cur)->prefix);
6522
if (attrDecl)
6523
break;
6524
}
6525
}
6526
cur++;
6527
}
6528
xmlFree(nsList);
6529
}
6530
if (tmpstr != NULL)
6531
xmlFree(tmpstr);
6532
/*
6533
* Only default/fixed attrs are relevant.
6534
*/
6535
if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6536
return((xmlAttrPtr) attrDecl);
6537
}
6538
#endif /* LIBXML_TREE_ENABLED */
6539
return(NULL);
6540
}
6541
6542
static xmlChar*
6543
xmlGetPropNodeValueInternal(const xmlAttr *prop)
6544
{
6545
if (prop == NULL)
6546
return(NULL);
6547
if (prop->type == XML_ATTRIBUTE_NODE) {
6548
/*
6549
* Note that we return at least the empty string.
6550
* TODO: Do we really always want that?
6551
*/
6552
if (prop->children != NULL) {
6553
if ((prop->children->next == NULL) &&
6554
((prop->children->type == XML_TEXT_NODE) ||
6555
(prop->children->type == XML_CDATA_SECTION_NODE)))
6556
{
6557
/*
6558
* Optimization for the common case: only 1 text node.
6559
*/
6560
return(xmlStrdup(prop->children->content));
6561
} else {
6562
xmlChar *ret;
6563
6564
ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6565
if (ret != NULL)
6566
return(ret);
6567
}
6568
}
6569
return(xmlStrdup((xmlChar *)""));
6570
} else if (prop->type == XML_ATTRIBUTE_DECL) {
6571
return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6572
}
6573
return(NULL);
6574
}
6575
6576
/**
6577
* xmlHasProp:
6578
* @node: the node
6579
* @name: the attribute name
6580
*
6581
* Search an attribute associated to a node
6582
* This function also looks in DTD attribute declaration for #FIXED or
6583
* default declaration values unless DTD use has been turned off.
6584
*
6585
* Returns the attribute or the attribute declaration or NULL if
6586
* neither was found.
6587
*/
6588
xmlAttrPtr
6589
xmlHasProp(const xmlNode *node, const xmlChar *name) {
6590
xmlAttrPtr prop;
6591
xmlDocPtr doc;
6592
6593
if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6594
return(NULL);
6595
/*
6596
* Check on the properties attached to the node
6597
*/
6598
prop = node->properties;
6599
while (prop != NULL) {
6600
if (xmlStrEqual(prop->name, name)) {
6601
return(prop);
6602
}
6603
prop = prop->next;
6604
}
6605
if (!xmlCheckDTD) return(NULL);
6606
6607
/*
6608
* Check if there is a default declaration in the internal
6609
* or external subsets
6610
*/
6611
doc = node->doc;
6612
if (doc != NULL) {
6613
xmlAttributePtr attrDecl;
6614
if (doc->intSubset != NULL) {
6615
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6616
if ((attrDecl == NULL) && (doc->extSubset != NULL))
6617
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6618
if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6619
/* return attribute declaration only if a default value is given
6620
(that includes #FIXED declarations) */
6621
return((xmlAttrPtr) attrDecl);
6622
}
6623
}
6624
return(NULL);
6625
}
6626
6627
/**
6628
* xmlHasNsProp:
6629
* @node: the node
6630
* @name: the attribute name
6631
* @nameSpace: the URI of the namespace
6632
*
6633
* Search for an attribute associated to a node
6634
* This attribute has to be anchored in the namespace specified.
6635
* This does the entity substitution.
6636
* This function looks in DTD attribute declaration for #FIXED or
6637
* default declaration values unless DTD use has been turned off.
6638
* Note that a namespace of NULL indicates to use the default namespace.
6639
*
6640
* Returns the attribute or the attribute declaration or NULL
6641
* if neither was found.
6642
*/
6643
xmlAttrPtr
6644
xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
6645
6646
return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
6647
}
6648
6649
/**
6650
* xmlGetProp:
6651
* @node: the node
6652
* @name: the attribute name
6653
*
6654
* Search and get the value of an attribute associated to a node
6655
* This does the entity substitution.
6656
* This function looks in DTD attribute declaration for #FIXED or
6657
* default declaration values unless DTD use has been turned off.
6658
* NOTE: this function acts independently of namespaces associated
6659
* to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6660
* for namespace aware processing.
6661
*
6662
* Returns the attribute value or NULL if not found.
6663
* It's up to the caller to free the memory with xmlFree().
6664
*/
6665
xmlChar *
6666
xmlGetProp(const xmlNode *node, const xmlChar *name) {
6667
xmlAttrPtr prop;
6668
6669
prop = xmlHasProp(node, name);
6670
if (prop == NULL)
6671
return(NULL);
6672
return(xmlGetPropNodeValueInternal(prop));
6673
}
6674
6675
/**
6676
* xmlGetNoNsProp:
6677
* @node: the node
6678
* @name: the attribute name
6679
*
6680
* Search and get the value of an attribute associated to a node
6681
* This does the entity substitution.
6682
* This function looks in DTD attribute declaration for #FIXED or
6683
* default declaration values unless DTD use has been turned off.
6684
* This function is similar to xmlGetProp except it will accept only
6685
* an attribute in no namespace.
6686
*
6687
* Returns the attribute value or NULL if not found.
6688
* It's up to the caller to free the memory with xmlFree().
6689
*/
6690
xmlChar *
6691
xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) {
6692
xmlAttrPtr prop;
6693
6694
prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6695
if (prop == NULL)
6696
return(NULL);
6697
return(xmlGetPropNodeValueInternal(prop));
6698
}
6699
6700
/**
6701
* xmlGetNsProp:
6702
* @node: the node
6703
* @name: the attribute name
6704
* @nameSpace: the URI of the namespace
6705
*
6706
* Search and get the value of an attribute associated to a node
6707
* This attribute has to be anchored in the namespace specified.
6708
* This does the entity substitution.
6709
* This function looks in DTD attribute declaration for #FIXED or
6710
* default declaration values unless DTD use has been turned off.
6711
*
6712
* Returns the attribute value or NULL if not found.
6713
* It's up to the caller to free the memory with xmlFree().
6714
*/
6715
xmlChar *
6716
xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
6717
xmlAttrPtr prop;
6718
6719
prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6720
if (prop == NULL)
6721
return(NULL);
6722
return(xmlGetPropNodeValueInternal(prop));
6723
}
6724
6725
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6726
/**
6727
* xmlUnsetProp:
6728
* @node: the node
6729
* @name: the attribute name
6730
*
6731
* Remove an attribute carried by a node.
6732
* This handles only attributes in no namespace.
6733
* Returns 0 if successful, -1 if not found
6734
*/
6735
int
6736
xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6737
xmlAttrPtr prop;
6738
6739
prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6740
if (prop == NULL)
6741
return(-1);
6742
xmlUnlinkNode((xmlNodePtr) prop);
6743
xmlFreeProp(prop);
6744
return(0);
6745
}
6746
6747
/**
6748
* xmlUnsetNsProp:
6749
* @node: the node
6750
* @ns: the namespace definition
6751
* @name: the attribute name
6752
*
6753
* Remove an attribute carried by a node.
6754
* Returns 0 if successful, -1 if not found
6755
*/
6756
int
6757
xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6758
xmlAttrPtr prop;
6759
6760
prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6761
if (prop == NULL)
6762
return(-1);
6763
xmlUnlinkNode((xmlNodePtr) prop);
6764
xmlFreeProp(prop);
6765
return(0);
6766
}
6767
#endif
6768
6769
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
6770
/**
6771
* xmlSetProp:
6772
* @node: the node
6773
* @name: the attribute name (a QName)
6774
* @value: the attribute value
6775
*
6776
* Set (or reset) an attribute carried by a node.
6777
* If @name has a prefix, then the corresponding
6778
* namespace-binding will be used, if in scope; it is an
6779
* error it there's no such ns-binding for the prefix in
6780
* scope.
6781
* Returns the attribute pointer.
6782
*
6783
*/
6784
xmlAttrPtr
6785
xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
6786
int len;
6787
const xmlChar *nqname;
6788
6789
if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
6790
return(NULL);
6791
6792
/*
6793
* handle QNames
6794
*/
6795
nqname = xmlSplitQName3(name, &len);
6796
if (nqname != NULL) {
6797
xmlNsPtr ns;
6798
xmlChar *prefix = xmlStrndup(name, len);
6799
ns = xmlSearchNs(node->doc, node, prefix);
6800
if (prefix != NULL)
6801
xmlFree(prefix);
6802
if (ns != NULL)
6803
return(xmlSetNsProp(node, ns, nqname, value));
6804
}
6805
return(xmlSetNsProp(node, NULL, name, value));
6806
}
6807
6808
/**
6809
* xmlSetNsProp:
6810
* @node: the node
6811
* @ns: the namespace definition
6812
* @name: the attribute name
6813
* @value: the attribute value
6814
*
6815
* Set (or reset) an attribute carried by a node.
6816
* The ns structure must be in scope, this is not checked
6817
*
6818
* Returns the attribute pointer.
6819
*/
6820
xmlAttrPtr
6821
xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6822
const xmlChar *value)
6823
{
6824
xmlAttrPtr prop;
6825
6826
if (ns && (ns->href == NULL))
6827
return(NULL);
6828
prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6829
if (prop != NULL) {
6830
/*
6831
* Modify the attribute's value.
6832
*/
6833
if (prop->atype == XML_ATTRIBUTE_ID) {
6834
xmlRemoveID(node->doc, prop);
6835
prop->atype = XML_ATTRIBUTE_ID;
6836
}
6837
if (prop->children != NULL)
6838
xmlFreeNodeList(prop->children);
6839
prop->children = NULL;
6840
prop->last = NULL;
6841
prop->ns = ns;
6842
if (value != NULL) {
6843
xmlNodePtr tmp;
6844
6845
prop->children = xmlNewDocText(node->doc, value);
6846
prop->last = NULL;
6847
tmp = prop->children;
6848
while (tmp != NULL) {
6849
tmp->parent = (xmlNodePtr) prop;
6850
if (tmp->next == NULL)
6851
prop->last = tmp;
6852
tmp = tmp->next;
6853
}
6854
}
6855
if (prop->atype == XML_ATTRIBUTE_ID)
6856
xmlAddID(NULL, node->doc, value, prop);
6857
return(prop);
6858
}
6859
/*
6860
* No equal attr found; create a new one.
6861
*/
6862
return(xmlNewPropInternal(node, ns, name, value, 0));
6863
}
6864
6865
#endif /* LIBXML_TREE_ENABLED */
6866
6867
/**
6868
* xmlNodeIsText:
6869
* @node: the node
6870
*
6871
* Is this node a Text node ?
6872
* Returns 1 yes, 0 no
6873
*/
6874
int
6875
xmlNodeIsText(const xmlNode *node) {
6876
if (node == NULL) return(0);
6877
6878
if (node->type == XML_TEXT_NODE) return(1);
6879
return(0);
6880
}
6881
6882
/**
6883
* xmlIsBlankNode:
6884
* @node: the node
6885
*
6886
* Checks whether this node is an empty or whitespace only
6887
* (and possibly ignorable) text-node.
6888
*
6889
* Returns 1 yes, 0 no
6890
*/
6891
int
6892
xmlIsBlankNode(const xmlNode *node) {
6893
const xmlChar *cur;
6894
if (node == NULL) return(0);
6895
6896
if ((node->type != XML_TEXT_NODE) &&
6897
(node->type != XML_CDATA_SECTION_NODE))
6898
return(0);
6899
if (node->content == NULL) return(1);
6900
cur = node->content;
6901
while (*cur != 0) {
6902
if (!IS_BLANK_CH(*cur)) return(0);
6903
cur++;
6904
}
6905
6906
return(1);
6907
}
6908
6909
/**
6910
* xmlTextConcat:
6911
* @node: the node
6912
* @content: the content
6913
* @len: @content length
6914
*
6915
* Concat the given string at the end of the existing node content
6916
*
6917
* Returns -1 in case of error, 0 otherwise
6918
*/
6919
6920
int
6921
xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
6922
if (node == NULL) return(-1);
6923
6924
if ((node->type != XML_TEXT_NODE) &&
6925
(node->type != XML_CDATA_SECTION_NODE) &&
6926
(node->type != XML_COMMENT_NODE) &&
6927
(node->type != XML_PI_NODE)) {
6928
return(-1);
6929
}
6930
/* need to check if content is currently in the dictionary */
6931
if ((node->content == (xmlChar *) &(node->properties)) ||
6932
((node->doc != NULL) && (node->doc->dict != NULL) &&
6933
xmlDictOwns(node->doc->dict, node->content))) {
6934
node->content = xmlStrncatNew(node->content, content, len);
6935
} else {
6936
node->content = xmlStrncat(node->content, content, len);
6937
}
6938
node->properties = NULL;
6939
if (node->content == NULL)
6940
return(-1);
6941
return(0);
6942
}
6943
6944
/************************************************************************
6945
* *
6946
* Output : to a FILE or in memory *
6947
* *
6948
************************************************************************/
6949
6950
/**
6951
* xmlBufferCreate:
6952
*
6953
* routine to create an XML buffer.
6954
* returns the new structure.
6955
*/
6956
xmlBufferPtr
6957
xmlBufferCreate(void) {
6958
xmlBufferPtr ret;
6959
6960
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6961
if (ret == NULL) {
6962
xmlTreeErrMemory("creating buffer");
6963
return(NULL);
6964
}
6965
ret->use = 0;
6966
ret->size = xmlDefaultBufferSize;
6967
ret->alloc = xmlBufferAllocScheme;
6968
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
6969
if (ret->content == NULL) {
6970
xmlTreeErrMemory("creating buffer");
6971
xmlFree(ret);
6972
return(NULL);
6973
}
6974
ret->content[0] = 0;
6975
ret->contentIO = NULL;
6976
return(ret);
6977
}
6978
6979
/**
6980
* xmlBufferCreateSize:
6981
* @size: initial size of buffer
6982
*
6983
* routine to create an XML buffer.
6984
* returns the new structure.
6985
*/
6986
xmlBufferPtr
6987
xmlBufferCreateSize(size_t size) {
6988
xmlBufferPtr ret;
6989
6990
if (size >= UINT_MAX)
6991
return(NULL);
6992
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6993
if (ret == NULL) {
6994
xmlTreeErrMemory("creating buffer");
6995
return(NULL);
6996
}
6997
ret->use = 0;
6998
ret->alloc = xmlBufferAllocScheme;
6999
ret->size = (size ? size + 1 : 0); /* +1 for ending null */
7000
if (ret->size){
7001
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
7002
if (ret->content == NULL) {
7003
xmlTreeErrMemory("creating buffer");
7004
xmlFree(ret);
7005
return(NULL);
7006
}
7007
ret->content[0] = 0;
7008
} else
7009
ret->content = NULL;
7010
ret->contentIO = NULL;
7011
return(ret);
7012
}
7013
7014
/**
7015
* xmlBufferDetach:
7016
* @buf: the buffer
7017
*
7018
* Remove the string contained in a buffer and gie it back to the
7019
* caller. The buffer is reset to an empty content.
7020
* This doesn't work with immutable buffers as they can't be reset.
7021
*
7022
* Returns the previous string contained by the buffer.
7023
*/
7024
xmlChar *
7025
xmlBufferDetach(xmlBufferPtr buf) {
7026
xmlChar *ret;
7027
7028
if (buf == NULL)
7029
return(NULL);
7030
7031
ret = buf->content;
7032
buf->content = NULL;
7033
buf->size = 0;
7034
buf->use = 0;
7035
7036
return ret;
7037
}
7038
7039
7040
/**
7041
* xmlBufferCreateStatic:
7042
* @mem: the memory area
7043
* @size: the size in byte
7044
*
7045
* Returns an XML buffer initialized with bytes.
7046
*/
7047
xmlBufferPtr
7048
xmlBufferCreateStatic(void *mem, size_t size) {
7049
xmlBufferPtr buf = xmlBufferCreateSize(size);
7050
7051
xmlBufferAdd(buf, mem, size);
7052
return(buf);
7053
}
7054
7055
/**
7056
* xmlBufferSetAllocationScheme:
7057
* @buf: the buffer to tune
7058
* @scheme: allocation scheme to use
7059
*
7060
* Sets the allocation scheme for this buffer
7061
*/
7062
void
7063
xmlBufferSetAllocationScheme(xmlBufferPtr buf,
7064
xmlBufferAllocationScheme scheme) {
7065
if (buf == NULL) {
7066
return;
7067
}
7068
if (buf->alloc == XML_BUFFER_ALLOC_IO) return;
7069
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
7070
(scheme == XML_BUFFER_ALLOC_EXACT) ||
7071
(scheme == XML_BUFFER_ALLOC_HYBRID))
7072
buf->alloc = scheme;
7073
}
7074
7075
/**
7076
* xmlBufferFree:
7077
* @buf: the buffer to free
7078
*
7079
* Frees an XML buffer. It frees both the content and the structure which
7080
* encapsulate it.
7081
*/
7082
void
7083
xmlBufferFree(xmlBufferPtr buf) {
7084
if (buf == NULL) {
7085
return;
7086
}
7087
7088
if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7089
(buf->contentIO != NULL)) {
7090
xmlFree(buf->contentIO);
7091
} else if (buf->content != NULL) {
7092
xmlFree(buf->content);
7093
}
7094
xmlFree(buf);
7095
}
7096
7097
/**
7098
* xmlBufferEmpty:
7099
* @buf: the buffer
7100
*
7101
* empty a buffer.
7102
*/
7103
void
7104
xmlBufferEmpty(xmlBufferPtr buf) {
7105
if (buf == NULL) return;
7106
if (buf->content == NULL) return;
7107
buf->use = 0;
7108
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7109
size_t start_buf = buf->content - buf->contentIO;
7110
7111
buf->size += start_buf;
7112
buf->content = buf->contentIO;
7113
buf->content[0] = 0;
7114
} else {
7115
buf->content[0] = 0;
7116
}
7117
}
7118
7119
/**
7120
* xmlBufferShrink:
7121
* @buf: the buffer to dump
7122
* @len: the number of xmlChar to remove
7123
*
7124
* Remove the beginning of an XML buffer.
7125
*
7126
* Returns the number of #xmlChar removed, or -1 in case of failure.
7127
*/
7128
int
7129
xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
7130
if (buf == NULL) return(-1);
7131
if (len == 0) return(0);
7132
if (len > buf->use) return(-1);
7133
7134
buf->use -= len;
7135
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7136
/*
7137
* we just move the content pointer, but also make sure
7138
* the perceived buffer size has shrunk accordingly
7139
*/
7140
buf->content += len;
7141
buf->size -= len;
7142
7143
/*
7144
* sometimes though it maybe be better to really shrink
7145
* on IO buffers
7146
*/
7147
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7148
size_t start_buf = buf->content - buf->contentIO;
7149
if (start_buf >= buf->size) {
7150
memmove(buf->contentIO, &buf->content[0], buf->use);
7151
buf->content = buf->contentIO;
7152
buf->content[buf->use] = 0;
7153
buf->size += start_buf;
7154
}
7155
}
7156
} else {
7157
memmove(buf->content, &buf->content[len], buf->use);
7158
buf->content[buf->use] = 0;
7159
}
7160
return(len);
7161
}
7162
7163
/**
7164
* xmlBufferGrow:
7165
* @buf: the buffer
7166
* @len: the minimum free size to allocate
7167
*
7168
* Grow the available space of an XML buffer.
7169
*
7170
* Returns the new available space or -1 in case of error
7171
*/
7172
int
7173
xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7174
unsigned int size;
7175
xmlChar *newbuf;
7176
7177
if (buf == NULL) return(-1);
7178
7179
if (len < buf->size - buf->use)
7180
return(0);
7181
if (len >= UINT_MAX - buf->use) {
7182
xmlTreeErrMemory("growing buffer past UINT_MAX");
7183
return(-1);
7184
}
7185
7186
if (buf->size > (size_t) len) {
7187
size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
7188
} else {
7189
size = buf->use + len;
7190
size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
7191
}
7192
7193
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7194
size_t start_buf = buf->content - buf->contentIO;
7195
7196
newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7197
if (newbuf == NULL) {
7198
xmlTreeErrMemory("growing buffer");
7199
return(-1);
7200
}
7201
buf->contentIO = newbuf;
7202
buf->content = newbuf + start_buf;
7203
} else {
7204
newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7205
if (newbuf == NULL) {
7206
xmlTreeErrMemory("growing buffer");
7207
return(-1);
7208
}
7209
buf->content = newbuf;
7210
}
7211
buf->size = size;
7212
return(buf->size - buf->use - 1);
7213
}
7214
7215
/**
7216
* xmlBufferDump:
7217
* @file: the file output
7218
* @buf: the buffer to dump
7219
*
7220
* Dumps an XML buffer to a FILE *.
7221
* Returns the number of #xmlChar written
7222
*/
7223
int
7224
xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7225
size_t ret;
7226
7227
if (buf == NULL) {
7228
return(0);
7229
}
7230
if (buf->content == NULL) {
7231
return(0);
7232
}
7233
if (file == NULL)
7234
file = stdout;
7235
ret = fwrite(buf->content, 1, buf->use, file);
7236
return(ret > INT_MAX ? INT_MAX : ret);
7237
}
7238
7239
/**
7240
* xmlBufferContent:
7241
* @buf: the buffer
7242
*
7243
* Function to extract the content of a buffer
7244
*
7245
* Returns the internal content
7246
*/
7247
7248
const xmlChar *
7249
xmlBufferContent(const xmlBuffer *buf)
7250
{
7251
if(!buf)
7252
return NULL;
7253
7254
return buf->content;
7255
}
7256
7257
/**
7258
* xmlBufferLength:
7259
* @buf: the buffer
7260
*
7261
* Function to get the length of a buffer
7262
*
7263
* Returns the length of data in the internal content
7264
*/
7265
7266
int
7267
xmlBufferLength(const xmlBuffer *buf)
7268
{
7269
if(!buf)
7270
return 0;
7271
7272
return buf->use;
7273
}
7274
7275
/**
7276
* xmlBufferResize:
7277
* @buf: the buffer to resize
7278
* @size: the desired size
7279
*
7280
* Resize a buffer to accommodate minimum size of @size.
7281
*
7282
* Returns 0 in case of problems, 1 otherwise
7283
*/
7284
int
7285
xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7286
{
7287
unsigned int newSize;
7288
xmlChar* rebuf = NULL;
7289
size_t start_buf;
7290
7291
if (buf == NULL)
7292
return(0);
7293
7294
/* Don't resize if we don't have to */
7295
if (size < buf->size)
7296
return 1;
7297
7298
if (size > UINT_MAX - 10) {
7299
xmlTreeErrMemory("growing buffer past UINT_MAX");
7300
return 0;
7301
}
7302
7303
/* figure out new size */
7304
switch (buf->alloc){
7305
case XML_BUFFER_ALLOC_IO:
7306
case XML_BUFFER_ALLOC_DOUBLEIT:
7307
/*take care of empty case*/
7308
if (buf->size == 0)
7309
newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7310
else
7311
newSize = buf->size;
7312
while (size > newSize) {
7313
if (newSize > UINT_MAX / 2) {
7314
xmlTreeErrMemory("growing buffer");
7315
return 0;
7316
}
7317
newSize *= 2;
7318
}
7319
break;
7320
case XML_BUFFER_ALLOC_EXACT:
7321
newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7322
break;
7323
case XML_BUFFER_ALLOC_HYBRID:
7324
if (buf->use < BASE_BUFFER_SIZE)
7325
newSize = size;
7326
else {
7327
newSize = buf->size;
7328
while (size > newSize) {
7329
if (newSize > UINT_MAX / 2) {
7330
xmlTreeErrMemory("growing buffer");
7331
return 0;
7332
}
7333
newSize *= 2;
7334
}
7335
}
7336
break;
7337
7338
default:
7339
newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7340
break;
7341
}
7342
7343
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7344
start_buf = buf->content - buf->contentIO;
7345
7346
if (start_buf > newSize) {
7347
/* move data back to start */
7348
memmove(buf->contentIO, buf->content, buf->use);
7349
buf->content = buf->contentIO;
7350
buf->content[buf->use] = 0;
7351
buf->size += start_buf;
7352
} else {
7353
rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7354
if (rebuf == NULL) {
7355
xmlTreeErrMemory("growing buffer");
7356
return 0;
7357
}
7358
buf->contentIO = rebuf;
7359
buf->content = rebuf + start_buf;
7360
}
7361
} else {
7362
if (buf->content == NULL) {
7363
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7364
buf->use = 0;
7365
rebuf[buf->use] = 0;
7366
} else if (buf->size - buf->use < 100) {
7367
rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7368
} else {
7369
/*
7370
* if we are reallocating a buffer far from being full, it's
7371
* better to make a new allocation and copy only the used range
7372
* and free the old one.
7373
*/
7374
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7375
if (rebuf != NULL) {
7376
memcpy(rebuf, buf->content, buf->use);
7377
xmlFree(buf->content);
7378
rebuf[buf->use] = 0;
7379
}
7380
}
7381
if (rebuf == NULL) {
7382
xmlTreeErrMemory("growing buffer");
7383
return 0;
7384
}
7385
buf->content = rebuf;
7386
}
7387
buf->size = newSize;
7388
7389
return 1;
7390
}
7391
7392
/**
7393
* xmlBufferAdd:
7394
* @buf: the buffer to dump
7395
* @str: the #xmlChar string
7396
* @len: the number of #xmlChar to add
7397
*
7398
* Add a string range to an XML buffer. if len == -1, the length of
7399
* str is recomputed.
7400
*
7401
* Returns 0 successful, a positive error code number otherwise
7402
* and -1 in case of internal or API error.
7403
*/
7404
int
7405
xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7406
unsigned int needSize;
7407
7408
if ((str == NULL) || (buf == NULL)) {
7409
return -1;
7410
}
7411
if (len < -1) {
7412
return -1;
7413
}
7414
if (len == 0) return 0;
7415
7416
if (len < 0)
7417
len = xmlStrlen(str);
7418
7419
if (len < 0) return -1;
7420
if (len == 0) return 0;
7421
7422
/* Note that both buf->size and buf->use can be zero here. */
7423
if ((unsigned) len >= buf->size - buf->use) {
7424
if ((unsigned) len >= UINT_MAX - buf->use) {
7425
xmlTreeErrMemory("growing buffer past UINT_MAX");
7426
return XML_ERR_NO_MEMORY;
7427
}
7428
needSize = buf->use + len + 1;
7429
if (!xmlBufferResize(buf, needSize)){
7430
xmlTreeErrMemory("growing buffer");
7431
return XML_ERR_NO_MEMORY;
7432
}
7433
}
7434
7435
memmove(&buf->content[buf->use], str, len);
7436
buf->use += len;
7437
buf->content[buf->use] = 0;
7438
return 0;
7439
}
7440
7441
/**
7442
* xmlBufferAddHead:
7443
* @buf: the buffer
7444
* @str: the #xmlChar string
7445
* @len: the number of #xmlChar to add
7446
*
7447
* Add a string range to the beginning of an XML buffer.
7448
* if len == -1, the length of @str is recomputed.
7449
*
7450
* Returns 0 successful, a positive error code number otherwise
7451
* and -1 in case of internal or API error.
7452
*/
7453
int
7454
xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7455
unsigned int needSize;
7456
7457
if (buf == NULL)
7458
return(-1);
7459
if (str == NULL) {
7460
return -1;
7461
}
7462
if (len < -1) {
7463
return -1;
7464
}
7465
if (len == 0) return 0;
7466
7467
if (len < 0)
7468
len = xmlStrlen(str);
7469
7470
if (len <= 0) return -1;
7471
7472
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7473
size_t start_buf = buf->content - buf->contentIO;
7474
7475
if (start_buf > (unsigned int) len) {
7476
/*
7477
* We can add it in the space previously shrunk
7478
*/
7479
buf->content -= len;
7480
memmove(&buf->content[0], str, len);
7481
buf->use += len;
7482
buf->size += len;
7483
buf->content[buf->use] = 0;
7484
return(0);
7485
}
7486
}
7487
/* Note that both buf->size and buf->use can be zero here. */
7488
if ((unsigned) len >= buf->size - buf->use) {
7489
if ((unsigned) len >= UINT_MAX - buf->use) {
7490
xmlTreeErrMemory("growing buffer past UINT_MAX");
7491
return(-1);
7492
}
7493
needSize = buf->use + len + 1;
7494
if (!xmlBufferResize(buf, needSize)){
7495
xmlTreeErrMemory("growing buffer");
7496
return XML_ERR_NO_MEMORY;
7497
}
7498
}
7499
7500
memmove(&buf->content[len], &buf->content[0], buf->use);
7501
memmove(&buf->content[0], str, len);
7502
buf->use += len;
7503
buf->content[buf->use] = 0;
7504
return 0;
7505
}
7506
7507
/**
7508
* xmlBufferCat:
7509
* @buf: the buffer to add to
7510
* @str: the #xmlChar string
7511
*
7512
* Append a zero terminated string to an XML buffer.
7513
*
7514
* Returns 0 successful, a positive error code number otherwise
7515
* and -1 in case of internal or API error.
7516
*/
7517
int
7518
xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
7519
if (buf == NULL)
7520
return(-1);
7521
if (str == NULL) return -1;
7522
return xmlBufferAdd(buf, str, -1);
7523
}
7524
7525
/**
7526
* xmlBufferCCat:
7527
* @buf: the buffer to dump
7528
* @str: the C char string
7529
*
7530
* Append a zero terminated C string to an XML buffer.
7531
*
7532
* Returns 0 successful, a positive error code number otherwise
7533
* and -1 in case of internal or API error.
7534
*/
7535
int
7536
xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7537
return xmlBufferCat(buf, (const xmlChar *) str);
7538
}
7539
7540
/**
7541
* xmlBufferWriteCHAR:
7542
* @buf: the XML buffer
7543
* @string: the string to add
7544
*
7545
* routine which manages and grows an output buffer. This one adds
7546
* xmlChars at the end of the buffer.
7547
*/
7548
void
7549
xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7550
if (buf == NULL)
7551
return;
7552
xmlBufferCat(buf, string);
7553
}
7554
7555
/**
7556
* xmlBufferWriteChar:
7557
* @buf: the XML buffer output
7558
* @string: the string to add
7559
*
7560
* routine which manage and grows an output buffer. This one add
7561
* C chars at the end of the array.
7562
*/
7563
void
7564
xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
7565
if (buf == NULL)
7566
return;
7567
xmlBufferCCat(buf, string);
7568
}
7569
7570
7571
/**
7572
* xmlBufferWriteQuotedString:
7573
* @buf: the XML buffer output
7574
* @string: the string to add
7575
*
7576
* routine which manage and grows an output buffer. This one writes
7577
* a quoted or double quoted #xmlChar string, checking first if it holds
7578
* quote or double-quotes internally
7579
*/
7580
void
7581
xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
7582
const xmlChar *cur, *base;
7583
if (buf == NULL)
7584
return;
7585
if (xmlStrchr(string, '\"')) {
7586
if (xmlStrchr(string, '\'')) {
7587
xmlBufferCCat(buf, "\"");
7588
base = cur = string;
7589
while(*cur != 0){
7590
if(*cur == '"'){
7591
if (base != cur)
7592
xmlBufferAdd(buf, base, cur - base);
7593
xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7594
cur++;
7595
base = cur;
7596
}
7597
else {
7598
cur++;
7599
}
7600
}
7601
if (base != cur)
7602
xmlBufferAdd(buf, base, cur - base);
7603
xmlBufferCCat(buf, "\"");
7604
}
7605
else{
7606
xmlBufferCCat(buf, "\'");
7607
xmlBufferCat(buf, string);
7608
xmlBufferCCat(buf, "\'");
7609
}
7610
} else {
7611
xmlBufferCCat(buf, "\"");
7612
xmlBufferCat(buf, string);
7613
xmlBufferCCat(buf, "\"");
7614
}
7615
}
7616
7617
7618
/**
7619
* xmlGetDocCompressMode:
7620
* @doc: the document
7621
*
7622
* get the compression ratio for a document, ZLIB based
7623
* Returns 0 (uncompressed) to 9 (max compression)
7624
*/
7625
int
7626
xmlGetDocCompressMode (const xmlDoc *doc) {
7627
if (doc == NULL) return(-1);
7628
return(doc->compression);
7629
}
7630
7631
/**
7632
* xmlSetDocCompressMode:
7633
* @doc: the document
7634
* @mode: the compression ratio
7635
*
7636
* set the compression ratio for a document, ZLIB based
7637
* Correct values: 0 (uncompressed) to 9 (max compression)
7638
*/
7639
void
7640
xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7641
if (doc == NULL) return;
7642
if (mode < 0) doc->compression = 0;
7643
else if (mode > 9) doc->compression = 9;
7644
else doc->compression = mode;
7645
}
7646
7647
/**
7648
* xmlGetCompressMode:
7649
*
7650
* get the default compression mode used, ZLIB based.
7651
* Returns 0 (uncompressed) to 9 (max compression)
7652
*/
7653
int
7654
xmlGetCompressMode(void)
7655
{
7656
return (xmlCompressMode);
7657
}
7658
7659
/**
7660
* xmlSetCompressMode:
7661
* @mode: the compression ratio
7662
*
7663
* set the default compression mode used, ZLIB based
7664
* Correct values: 0 (uncompressed) to 9 (max compression)
7665
*/
7666
void
7667
xmlSetCompressMode(int mode) {
7668
if (mode < 0) xmlCompressMode = 0;
7669
else if (mode > 9) xmlCompressMode = 9;
7670
else xmlCompressMode = mode;
7671
}
7672
7673
#define XML_TREE_NSMAP_PARENT -1
7674
#define XML_TREE_NSMAP_XML -2
7675
#define XML_TREE_NSMAP_DOC -3
7676
#define XML_TREE_NSMAP_CUSTOM -4
7677
7678
typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7679
struct xmlNsMapItem {
7680
xmlNsMapItemPtr next;
7681
xmlNsMapItemPtr prev;
7682
xmlNsPtr oldNs; /* old ns decl reference */
7683
xmlNsPtr newNs; /* new ns decl reference */
7684
int shadowDepth; /* Shadowed at this depth */
7685
/*
7686
* depth:
7687
* >= 0 == @node's ns-decls
7688
* -1 == @parent's ns-decls
7689
* -2 == the doc->oldNs XML ns-decl
7690
* -3 == the doc->oldNs storage ns-decls
7691
* -4 == ns-decls provided via custom ns-handling
7692
*/
7693
int depth;
7694
};
7695
7696
typedef struct xmlNsMap *xmlNsMapPtr;
7697
struct xmlNsMap {
7698
xmlNsMapItemPtr first;
7699
xmlNsMapItemPtr last;
7700
xmlNsMapItemPtr pool;
7701
};
7702
7703
#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7704
#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7705
#define XML_NSMAP_POP(m, i) \
7706
i = (m)->last; \
7707
(m)->last = (i)->prev; \
7708
if ((m)->last == NULL) \
7709
(m)->first = NULL; \
7710
else \
7711
(m)->last->next = NULL; \
7712
(i)->next = (m)->pool; \
7713
(m)->pool = i;
7714
7715
/*
7716
* xmlDOMWrapNsMapFree:
7717
* @map: the ns-map
7718
*
7719
* Frees the ns-map
7720
*/
7721
static void
7722
xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7723
{
7724
xmlNsMapItemPtr cur, tmp;
7725
7726
if (nsmap == NULL)
7727
return;
7728
cur = nsmap->pool;
7729
while (cur != NULL) {
7730
tmp = cur;
7731
cur = cur->next;
7732
xmlFree(tmp);
7733
}
7734
cur = nsmap->first;
7735
while (cur != NULL) {
7736
tmp = cur;
7737
cur = cur->next;
7738
xmlFree(tmp);
7739
}
7740
xmlFree(nsmap);
7741
}
7742
7743
/*
7744
* xmlDOMWrapNsMapAddItem:
7745
* @map: the ns-map
7746
* @oldNs: the old ns-struct
7747
* @newNs: the new ns-struct
7748
* @depth: depth and ns-kind information
7749
*
7750
* Adds an ns-mapping item.
7751
*/
7752
static xmlNsMapItemPtr
7753
xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
7754
xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
7755
{
7756
xmlNsMapItemPtr ret;
7757
xmlNsMapPtr map;
7758
7759
if (nsmap == NULL)
7760
return(NULL);
7761
if ((position != -1) && (position != 0))
7762
return(NULL);
7763
map = *nsmap;
7764
7765
if (map == NULL) {
7766
/*
7767
* Create the ns-map.
7768
*/
7769
map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7770
if (map == NULL) {
7771
xmlTreeErrMemory("allocating namespace map");
7772
return (NULL);
7773
}
7774
memset(map, 0, sizeof(struct xmlNsMap));
7775
*nsmap = map;
7776
}
7777
7778
if (map->pool != NULL) {
7779
/*
7780
* Reuse an item from the pool.
7781
*/
7782
ret = map->pool;
7783
map->pool = ret->next;
7784
memset(ret, 0, sizeof(struct xmlNsMapItem));
7785
} else {
7786
/*
7787
* Create a new item.
7788
*/
7789
ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7790
if (ret == NULL) {
7791
xmlTreeErrMemory("allocating namespace map item");
7792
return (NULL);
7793
}
7794
memset(ret, 0, sizeof(struct xmlNsMapItem));
7795
}
7796
7797
if (map->first == NULL) {
7798
/*
7799
* First ever.
7800
*/
7801
map->first = ret;
7802
map->last = ret;
7803
} else if (position == -1) {
7804
/*
7805
* Append.
7806
*/
7807
ret->prev = map->last;
7808
map->last->next = ret;
7809
map->last = ret;
7810
} else if (position == 0) {
7811
/*
7812
* Set on first position.
7813
*/
7814
map->first->prev = ret;
7815
ret->next = map->first;
7816
map->first = ret;
7817
}
7818
7819
ret->oldNs = oldNs;
7820
ret->newNs = newNs;
7821
ret->shadowDepth = -1;
7822
ret->depth = depth;
7823
return (ret);
7824
}
7825
7826
/*
7827
* xmlDOMWrapStoreNs:
7828
* @doc: the doc
7829
* @nsName: the namespace name
7830
* @prefix: the prefix
7831
*
7832
* Creates or reuses an xmlNs struct on doc->oldNs with
7833
* the given prefix and namespace name.
7834
*
7835
* Returns the acquired ns struct or NULL in case of an API
7836
* or internal error.
7837
*/
7838
static xmlNsPtr
7839
xmlDOMWrapStoreNs(xmlDocPtr doc,
7840
const xmlChar *nsName,
7841
const xmlChar *prefix)
7842
{
7843
xmlNsPtr ns;
7844
7845
if (doc == NULL)
7846
return (NULL);
7847
ns = xmlTreeEnsureXMLDecl(doc);
7848
if (ns == NULL)
7849
return (NULL);
7850
if (ns->next != NULL) {
7851
/* Reuse. */
7852
ns = ns->next;
7853
while (ns != NULL) {
7854
if (((ns->prefix == prefix) ||
7855
xmlStrEqual(ns->prefix, prefix)) &&
7856
xmlStrEqual(ns->href, nsName)) {
7857
return (ns);
7858
}
7859
if (ns->next == NULL)
7860
break;
7861
ns = ns->next;
7862
}
7863
}
7864
/* Create. */
7865
if (ns != NULL) {
7866
ns->next = xmlNewNs(NULL, nsName, prefix);
7867
return (ns->next);
7868
}
7869
return(NULL);
7870
}
7871
7872
/*
7873
* xmlDOMWrapNewCtxt:
7874
*
7875
* Allocates and initializes a new DOM-wrapper context.
7876
*
7877
* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal error.
7878
*/
7879
xmlDOMWrapCtxtPtr
7880
xmlDOMWrapNewCtxt(void)
7881
{
7882
xmlDOMWrapCtxtPtr ret;
7883
7884
ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7885
if (ret == NULL) {
7886
xmlTreeErrMemory("allocating DOM-wrapper context");
7887
return (NULL);
7888
}
7889
memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7890
return (ret);
7891
}
7892
7893
/*
7894
* xmlDOMWrapFreeCtxt:
7895
* @ctxt: the DOM-wrapper context
7896
*
7897
* Frees the DOM-wrapper context.
7898
*/
7899
void
7900
xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7901
{
7902
if (ctxt == NULL)
7903
return;
7904
if (ctxt->namespaceMap != NULL)
7905
xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7906
/*
7907
* TODO: Store the namespace map in the context.
7908
*/
7909
xmlFree(ctxt);
7910
}
7911
7912
/*
7913
* xmlTreeLookupNsListByPrefix:
7914
* @nsList: a list of ns-structs
7915
* @prefix: the searched prefix
7916
*
7917
* Searches for a ns-decl with the given prefix in @nsList.
7918
*
7919
* Returns the ns-decl if found, NULL if not found and on
7920
* API errors.
7921
*/
7922
static xmlNsPtr
7923
xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7924
{
7925
if (nsList == NULL)
7926
return (NULL);
7927
{
7928
xmlNsPtr ns;
7929
ns = nsList;
7930
do {
7931
if ((prefix == ns->prefix) ||
7932
xmlStrEqual(prefix, ns->prefix)) {
7933
return (ns);
7934
}
7935
ns = ns->next;
7936
} while (ns != NULL);
7937
}
7938
return (NULL);
7939
}
7940
7941
/*
7942
*
7943
* xmlDOMWrapNSNormGatherInScopeNs:
7944
* @map: the namespace map
7945
* @node: the node to start with
7946
*
7947
* Puts in-scope namespaces into the ns-map.
7948
*
7949
* Returns 0 on success, -1 on API or internal errors.
7950
*/
7951
static int
7952
xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
7953
xmlNodePtr node)
7954
{
7955
xmlNodePtr cur;
7956
xmlNsPtr ns;
7957
xmlNsMapItemPtr mi;
7958
int shadowed;
7959
7960
if ((map == NULL) || (*map != NULL))
7961
return (-1);
7962
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
7963
return (-1);
7964
/*
7965
* Get in-scope ns-decls of @parent.
7966
*/
7967
cur = node;
7968
while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7969
if (cur->type == XML_ELEMENT_NODE) {
7970
if (cur->nsDef != NULL) {
7971
ns = cur->nsDef;
7972
do {
7973
shadowed = 0;
7974
if (XML_NSMAP_NOTEMPTY(*map)) {
7975
/*
7976
* Skip shadowed prefixes.
7977
*/
7978
XML_NSMAP_FOREACH(*map, mi) {
7979
if ((ns->prefix == mi->newNs->prefix) ||
7980
xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7981
shadowed = 1;
7982
break;
7983
}
7984
}
7985
}
7986
/*
7987
* Insert mapping.
7988
*/
7989
mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
7990
ns, XML_TREE_NSMAP_PARENT);
7991
if (mi == NULL)
7992
return (-1);
7993
if (shadowed)
7994
mi->shadowDepth = 0;
7995
ns = ns->next;
7996
} while (ns != NULL);
7997
}
7998
}
7999
cur = cur->parent;
8000
}
8001
return (0);
8002
}
8003
8004
/*
8005
* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
8006
* otherwise copy it, when it was in the source-dict.
8007
*/
8008
#define XML_TREE_ADOPT_STR(str) \
8009
if (adoptStr && (str != NULL)) { \
8010
if (destDoc->dict) { \
8011
const xmlChar *old = str; \
8012
str = xmlDictLookup(destDoc->dict, str, -1); \
8013
if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
8014
(!xmlDictOwns(sourceDoc->dict, old))) \
8015
xmlFree((char *)old); \
8016
} else if ((sourceDoc) && (sourceDoc->dict) && \
8017
xmlDictOwns(sourceDoc->dict, str)) { \
8018
str = BAD_CAST xmlStrdup(str); \
8019
} \
8020
}
8021
8022
/*
8023
* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
8024
* put it in dest-dict or copy it.
8025
*/
8026
#define XML_TREE_ADOPT_STR_2(str) \
8027
if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
8028
(sourceDoc->dict != NULL) && \
8029
xmlDictOwns(sourceDoc->dict, cur->content)) { \
8030
if (destDoc->dict) \
8031
cur->content = (xmlChar *) \
8032
xmlDictLookup(destDoc->dict, cur->content, -1); \
8033
else \
8034
cur->content = xmlStrdup(BAD_CAST cur->content); \
8035
}
8036
8037
/*
8038
* xmlDOMWrapNSNormAddNsMapItem2:
8039
*
8040
* For internal use. Adds a ns-decl mapping.
8041
*
8042
* Returns 0 on success, -1 on internal errors.
8043
*/
8044
static int
8045
xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
8046
xmlNsPtr oldNs, xmlNsPtr newNs)
8047
{
8048
if (*list == NULL) {
8049
*list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
8050
if (*list == NULL) {
8051
xmlTreeErrMemory("alloc ns map item");
8052
return(-1);
8053
}
8054
*size = 3;
8055
*number = 0;
8056
} else if ((*number) >= (*size)) {
8057
*size *= 2;
8058
*list = (xmlNsPtr *) xmlRealloc(*list,
8059
(*size) * 2 * sizeof(xmlNsPtr));
8060
if (*list == NULL) {
8061
xmlTreeErrMemory("realloc ns map item");
8062
return(-1);
8063
}
8064
}
8065
(*list)[2 * (*number)] = oldNs;
8066
(*list)[2 * (*number) +1] = newNs;
8067
(*number)++;
8068
return (0);
8069
}
8070
8071
/*
8072
* xmlDOMWrapRemoveNode:
8073
* @ctxt: a DOM wrapper context
8074
* @doc: the doc
8075
* @node: the node to be removed.
8076
* @options: set of options, unused at the moment
8077
*
8078
* Unlinks the given node from its owner.
8079
* This will substitute ns-references to node->nsDef for
8080
* ns-references to doc->oldNs, thus ensuring the removed
8081
* branch to be autark wrt ns-references.
8082
*
8083
* NOTE: This function was not intensively tested.
8084
*
8085
* Returns 0 on success, 1 if the node is not supported,
8086
* -1 on API and internal errors.
8087
*/
8088
int
8089
xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8090
xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8091
{
8092
xmlNsPtr *list = NULL;
8093
int sizeList, nbList, i, j;
8094
xmlNsPtr ns;
8095
8096
if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8097
return (-1);
8098
8099
/* TODO: 0 or -1 ? */
8100
if (node->parent == NULL)
8101
return (0);
8102
8103
switch (node->type) {
8104
case XML_TEXT_NODE:
8105
case XML_CDATA_SECTION_NODE:
8106
case XML_ENTITY_REF_NODE:
8107
case XML_PI_NODE:
8108
case XML_COMMENT_NODE:
8109
xmlUnlinkNode(node);
8110
return (0);
8111
case XML_ELEMENT_NODE:
8112
case XML_ATTRIBUTE_NODE:
8113
break;
8114
default:
8115
return (1);
8116
}
8117
xmlUnlinkNode(node);
8118
/*
8119
* Save out-of-scope ns-references in doc->oldNs.
8120
*/
8121
do {
8122
switch (node->type) {
8123
case XML_ELEMENT_NODE:
8124
if ((ctxt == NULL) && (node->nsDef != NULL)) {
8125
ns = node->nsDef;
8126
do {
8127
if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8128
&nbList, ns, ns) == -1)
8129
goto internal_error;
8130
ns = ns->next;
8131
} while (ns != NULL);
8132
}
8133
/* Falls through. */
8134
case XML_ATTRIBUTE_NODE:
8135
if (node->ns != NULL) {
8136
/*
8137
* Find a mapping.
8138
*/
8139
if (list != NULL) {
8140
for (i = 0, j = 0; i < nbList; i++, j += 2) {
8141
if (node->ns == list[j]) {
8142
node->ns = list[++j];
8143
goto next_node;
8144
}
8145
}
8146
}
8147
ns = NULL;
8148
if (ctxt != NULL) {
8149
/*
8150
* User defined.
8151
*/
8152
} else {
8153
/*
8154
* Add to doc's oldNs.
8155
*/
8156
ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8157
node->ns->prefix);
8158
if (ns == NULL)
8159
goto internal_error;
8160
}
8161
if (ns != NULL) {
8162
/*
8163
* Add mapping.
8164
*/
8165
if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8166
&nbList, node->ns, ns) == -1)
8167
goto internal_error;
8168
}
8169
node->ns = ns;
8170
}
8171
if ((node->type == XML_ELEMENT_NODE) &&
8172
(node->properties != NULL)) {
8173
node = (xmlNodePtr) node->properties;
8174
continue;
8175
}
8176
break;
8177
default:
8178
goto next_sibling;
8179
}
8180
next_node:
8181
if ((node->type == XML_ELEMENT_NODE) &&
8182
(node->children != NULL)) {
8183
node = node->children;
8184
continue;
8185
}
8186
next_sibling:
8187
if (node == NULL)
8188
break;
8189
if (node->next != NULL)
8190
node = node->next;
8191
else {
8192
node = node->parent;
8193
goto next_sibling;
8194
}
8195
} while (node != NULL);
8196
8197
if (list != NULL)
8198
xmlFree(list);
8199
return (0);
8200
8201
internal_error:
8202
if (list != NULL)
8203
xmlFree(list);
8204
return (-1);
8205
}
8206
8207
/*
8208
* xmlSearchNsByNamespaceStrict:
8209
* @doc: the document
8210
* @node: the start node
8211
* @nsName: the searched namespace name
8212
* @retNs: the resulting ns-decl
8213
* @prefixed: if the found ns-decl must have a prefix (for attributes)
8214
*
8215
* Dynamically searches for a ns-declaration which matches
8216
* the given @nsName in the ancestor-or-self axis of @node.
8217
*
8218
* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8219
* and internal errors.
8220
*/
8221
static int
8222
xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8223
const xmlChar* nsName,
8224
xmlNsPtr *retNs, int prefixed)
8225
{
8226
xmlNodePtr cur, prev = NULL, out = NULL;
8227
xmlNsPtr ns, prevns;
8228
8229
if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8230
return (-1);
8231
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8232
return(-1);
8233
8234
*retNs = NULL;
8235
if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8236
*retNs = xmlTreeEnsureXMLDecl(doc);
8237
if (*retNs == NULL)
8238
return (-1);
8239
return (1);
8240
}
8241
cur = node;
8242
do {
8243
if (cur->type == XML_ELEMENT_NODE) {
8244
if (cur->nsDef != NULL) {
8245
for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8246
if (prefixed && (ns->prefix == NULL))
8247
continue;
8248
if (prev != NULL) {
8249
/*
8250
* Check the last level of ns-decls for a
8251
* shadowing prefix.
8252
*/
8253
prevns = prev->nsDef;
8254
do {
8255
if ((prevns->prefix == ns->prefix) ||
8256
((prevns->prefix != NULL) &&
8257
(ns->prefix != NULL) &&
8258
xmlStrEqual(prevns->prefix, ns->prefix))) {
8259
/*
8260
* Shadowed.
8261
*/
8262
break;
8263
}
8264
prevns = prevns->next;
8265
} while (prevns != NULL);
8266
if (prevns != NULL)
8267
continue;
8268
}
8269
/*
8270
* Ns-name comparison.
8271
*/
8272
if ((nsName == ns->href) ||
8273
xmlStrEqual(nsName, ns->href)) {
8274
/*
8275
* At this point the prefix can only be shadowed,
8276
* if we are the the (at least) 3rd level of
8277
* ns-decls.
8278
*/
8279
if (out) {
8280
int ret;
8281
8282
ret = xmlNsInScope(doc, node, prev, ns->prefix);
8283
if (ret < 0)
8284
return (-1);
8285
/*
8286
* TODO: Should we try to find a matching ns-name
8287
* only once? This here keeps on searching.
8288
* I think we should try further since, there might
8289
* be an other matching ns-decl with an unshadowed
8290
* prefix.
8291
*/
8292
if (! ret)
8293
continue;
8294
}
8295
*retNs = ns;
8296
return (1);
8297
}
8298
}
8299
out = prev;
8300
prev = cur;
8301
}
8302
} else if ((cur->type == XML_ENTITY_NODE) ||
8303
(cur->type == XML_ENTITY_DECL))
8304
return (0);
8305
cur = cur->parent;
8306
} while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8307
return (0);
8308
}
8309
8310
/*
8311
* xmlSearchNsByPrefixStrict:
8312
* @doc: the document
8313
* @node: the start node
8314
* @prefix: the searched namespace prefix
8315
* @retNs: the resulting ns-decl
8316
*
8317
* Dynamically searches for a ns-declaration which matches
8318
* the given @nsName in the ancestor-or-self axis of @node.
8319
*
8320
* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8321
* and internal errors.
8322
*/
8323
static int
8324
xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8325
const xmlChar* prefix,
8326
xmlNsPtr *retNs)
8327
{
8328
xmlNodePtr cur;
8329
xmlNsPtr ns;
8330
8331
if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL))
8332
return(-1);
8333
8334
if (retNs)
8335
*retNs = NULL;
8336
if (IS_STR_XML(prefix)) {
8337
if (retNs) {
8338
*retNs = xmlTreeEnsureXMLDecl(doc);
8339
if (*retNs == NULL)
8340
return (-1);
8341
}
8342
return (1);
8343
}
8344
cur = node;
8345
do {
8346
if (cur->type == XML_ELEMENT_NODE) {
8347
if (cur->nsDef != NULL) {
8348
ns = cur->nsDef;
8349
do {
8350
if ((prefix == ns->prefix) ||
8351
xmlStrEqual(prefix, ns->prefix))
8352
{
8353
/*
8354
* Disabled namespaces, e.g. xmlns:abc="".
8355
*/
8356
if (ns->href == NULL)
8357
return(0);
8358
if (retNs)
8359
*retNs = ns;
8360
return (1);
8361
}
8362
ns = ns->next;
8363
} while (ns != NULL);
8364
}
8365
} else if ((cur->type == XML_ENTITY_NODE) ||
8366
(cur->type == XML_ENTITY_DECL))
8367
return (0);
8368
cur = cur->parent;
8369
} while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8370
return (0);
8371
}
8372
8373
/*
8374
* xmlDOMWrapNSNormDeclareNsForced:
8375
* @doc: the doc
8376
* @elem: the element-node to declare on
8377
* @nsName: the namespace-name of the ns-decl
8378
* @prefix: the preferred prefix of the ns-decl
8379
* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8380
*
8381
* Declares a new namespace on @elem. It tries to use the
8382
* given @prefix; if a ns-decl with the given prefix is already existent
8383
* on @elem, it will generate an other prefix.
8384
*
8385
* Returns 1 if a ns-decl was found, 0 if not and -1 on API
8386
* and internal errors.
8387
*/
8388
static xmlNsPtr
8389
xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8390
xmlNodePtr elem,
8391
const xmlChar *nsName,
8392
const xmlChar *prefix,
8393
int checkShadow)
8394
{
8395
8396
xmlNsPtr ret;
8397
char buf[50];
8398
const xmlChar *pref;
8399
int counter = 0;
8400
8401
if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE))
8402
return(NULL);
8403
/*
8404
* Create a ns-decl on @anchor.
8405
*/
8406
pref = prefix;
8407
while (1) {
8408
/*
8409
* Lookup whether the prefix is unused in elem's ns-decls.
8410
*/
8411
if ((elem->nsDef != NULL) &&
8412
(xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8413
goto ns_next_prefix;
8414
if (checkShadow && elem->parent &&
8415
((xmlNodePtr) elem->parent->doc != elem->parent)) {
8416
/*
8417
* Does it shadow ancestor ns-decls?
8418
*/
8419
if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
8420
goto ns_next_prefix;
8421
}
8422
ret = xmlNewNs(NULL, nsName, pref);
8423
if (ret == NULL)
8424
return (NULL);
8425
if (elem->nsDef == NULL)
8426
elem->nsDef = ret;
8427
else {
8428
xmlNsPtr ns2 = elem->nsDef;
8429
while (ns2->next != NULL)
8430
ns2 = ns2->next;
8431
ns2->next = ret;
8432
}
8433
return (ret);
8434
ns_next_prefix:
8435
counter++;
8436
if (counter > 1000)
8437
return (NULL);
8438
if (prefix == NULL) {
8439
snprintf((char *) buf, sizeof(buf),
8440
"ns_%d", counter);
8441
} else
8442
snprintf((char *) buf, sizeof(buf),
8443
"%.30s_%d", (char *)prefix, counter);
8444
pref = BAD_CAST buf;
8445
}
8446
}
8447
8448
/*
8449
* xmlDOMWrapNSNormAcquireNormalizedNs:
8450
* @doc: the doc
8451
* @elem: the element-node to declare namespaces on
8452
* @ns: the ns-struct to use for the search
8453
* @retNs: the found/created ns-struct
8454
* @nsMap: the ns-map
8455
* @depth: the current tree depth
8456
* @ancestorsOnly: search in ancestor ns-decls only
8457
* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8458
*
8459
* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8460
* found it will either declare it on @elem, or store it in doc->oldNs.
8461
* If a new ns-decl needs to be declared on @elem, it tries to use the
8462
* @ns->prefix for it, if this prefix is already in use on @elem, it will
8463
* change the prefix or the new ns-decl.
8464
*
8465
* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8466
*/
8467
static int
8468
xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc,
8469
xmlNodePtr elem,
8470
xmlNsPtr ns,
8471
xmlNsPtr *retNs,
8472
xmlNsMapPtr *nsMap,
8473
8474
int depth,
8475
int ancestorsOnly,
8476
int prefixed)
8477
{
8478
xmlNsMapItemPtr mi;
8479
8480
if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
8481
(nsMap == NULL))
8482
return (-1);
8483
8484
*retNs = NULL;
8485
/*
8486
* Handle XML namespace.
8487
*/
8488
if (IS_STR_XML(ns->prefix)) {
8489
/*
8490
* Insert XML namespace mapping.
8491
*/
8492
*retNs = xmlTreeEnsureXMLDecl(doc);
8493
if (*retNs == NULL)
8494
return (-1);
8495
return (0);
8496
}
8497
/*
8498
* If the search should be done in ancestors only and no
8499
* @elem (the first ancestor) was specified, then skip the search.
8500
*/
8501
if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8502
(! (ancestorsOnly && (elem == NULL))))
8503
{
8504
/*
8505
* Try to find an equal ns-name in in-scope ns-decls.
8506
*/
8507
XML_NSMAP_FOREACH(*nsMap, mi) {
8508
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8509
/*
8510
* ancestorsOnly: This should be turned on to gain speed,
8511
* if one knows that the branch itself was already
8512
* ns-wellformed and no stale references existed.
8513
* I.e. it searches in the ancestor axis only.
8514
*/
8515
((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8516
/* Skip shadowed prefixes. */
8517
(mi->shadowDepth == -1) &&
8518
/* Skip xmlns="" or xmlns:foo="". */
8519
((mi->newNs->href != NULL) &&
8520
(mi->newNs->href[0] != 0)) &&
8521
/* Ensure a prefix if wanted. */
8522
((! prefixed) || (mi->newNs->prefix != NULL)) &&
8523
/* Equal ns name */
8524
((mi->newNs->href == ns->href) ||
8525
xmlStrEqual(mi->newNs->href, ns->href))) {
8526
/* Set the mapping. */
8527
mi->oldNs = ns;
8528
*retNs = mi->newNs;
8529
return (0);
8530
}
8531
}
8532
}
8533
/*
8534
* No luck, the namespace is out of scope or shadowed.
8535
*/
8536
if (elem == NULL) {
8537
xmlNsPtr tmpns;
8538
8539
/*
8540
* Store ns-decls in "oldNs" of the document-node.
8541
*/
8542
tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8543
if (tmpns == NULL)
8544
return (-1);
8545
/*
8546
* Insert mapping.
8547
*/
8548
if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
8549
tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8550
xmlFreeNs(tmpns);
8551
return (-1);
8552
}
8553
*retNs = tmpns;
8554
} else {
8555
xmlNsPtr tmpns;
8556
8557
tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8558
ns->prefix, 0);
8559
if (tmpns == NULL)
8560
return (-1);
8561
8562
if (*nsMap != NULL) {
8563
/*
8564
* Does it shadow ancestor ns-decls?
8565
*/
8566
XML_NSMAP_FOREACH(*nsMap, mi) {
8567
if ((mi->depth < depth) &&
8568
(mi->shadowDepth == -1) &&
8569
((ns->prefix == mi->newNs->prefix) ||
8570
xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8571
/*
8572
* Shadows.
8573
*/
8574
mi->shadowDepth = depth;
8575
break;
8576
}
8577
}
8578
}
8579
if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
8580
xmlFreeNs(tmpns);
8581
return (-1);
8582
}
8583
*retNs = tmpns;
8584
}
8585
return (0);
8586
}
8587
8588
typedef enum {
8589
XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8590
} xmlDOMReconcileNSOptions;
8591
8592
/*
8593
* xmlDOMWrapReconcileNamespaces:
8594
* @ctxt: DOM wrapper context, unused at the moment
8595
* @elem: the element-node
8596
* @options: option flags
8597
*
8598
* Ensures that ns-references point to ns-decls hold on element-nodes.
8599
* Ensures that the tree is namespace wellformed by creating additional
8600
* ns-decls where needed. Note that, since prefixes of already existent
8601
* ns-decls can be shadowed by this process, it could break QNames in
8602
* attribute values or element content.
8603
*
8604
* NOTE: This function was not intensively tested.
8605
*
8606
* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8607
*/
8608
8609
int
8610
xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8611
xmlNodePtr elem,
8612
int options)
8613
{
8614
int depth = -1, adoptns = 0, parnsdone = 0;
8615
xmlNsPtr ns, prevns;
8616
xmlDocPtr doc;
8617
xmlNodePtr cur, curElem = NULL;
8618
xmlNsMapPtr nsMap = NULL;
8619
xmlNsMapItemPtr /* topmi = NULL, */ mi;
8620
/* @ancestorsOnly should be set by an option flag. */
8621
int ancestorsOnly = 0;
8622
int optRemoveRedundantNS =
8623
((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8624
xmlNsPtr *listRedund = NULL;
8625
int sizeRedund = 0, nbRedund = 0, ret, i, j;
8626
8627
if ((elem == NULL) || (elem->doc == NULL) ||
8628
(elem->type != XML_ELEMENT_NODE))
8629
return (-1);
8630
8631
doc = elem->doc;
8632
cur = elem;
8633
do {
8634
switch (cur->type) {
8635
case XML_ELEMENT_NODE:
8636
adoptns = 1;
8637
curElem = cur;
8638
depth++;
8639
/*
8640
* Namespace declarations.
8641
*/
8642
if (cur->nsDef != NULL) {
8643
prevns = NULL;
8644
ns = cur->nsDef;
8645
while (ns != NULL) {
8646
if (! parnsdone) {
8647
if ((elem->parent) &&
8648
((xmlNodePtr) elem->parent->doc != elem->parent)) {
8649
/*
8650
* Gather ancestor in-scope ns-decls.
8651
*/
8652
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8653
elem->parent) == -1)
8654
goto internal_error;
8655
}
8656
parnsdone = 1;
8657
}
8658
8659
/*
8660
* Lookup the ns ancestor-axis for equal ns-decls in scope.
8661
*/
8662
if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8663
XML_NSMAP_FOREACH(nsMap, mi) {
8664
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8665
(mi->shadowDepth == -1) &&
8666
((ns->prefix == mi->newNs->prefix) ||
8667
xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8668
((ns->href == mi->newNs->href) ||
8669
xmlStrEqual(ns->href, mi->newNs->href)))
8670
{
8671
/*
8672
* A redundant ns-decl was found.
8673
* Add it to the list of redundant ns-decls.
8674
*/
8675
if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8676
&sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8677
goto internal_error;
8678
/*
8679
* Remove the ns-decl from the element-node.
8680
*/
8681
if (prevns)
8682
prevns->next = ns->next;
8683
else
8684
cur->nsDef = ns->next;
8685
goto next_ns_decl;
8686
}
8687
}
8688
}
8689
8690
/*
8691
* Skip ns-references handling if the referenced
8692
* ns-decl is declared on the same element.
8693
*/
8694
if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8695
adoptns = 0;
8696
/*
8697
* Does it shadow any ns-decl?
8698
*/
8699
if (XML_NSMAP_NOTEMPTY(nsMap)) {
8700
XML_NSMAP_FOREACH(nsMap, mi) {
8701
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8702
(mi->shadowDepth == -1) &&
8703
((ns->prefix == mi->newNs->prefix) ||
8704
xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8705
8706
mi->shadowDepth = depth;
8707
}
8708
}
8709
}
8710
/*
8711
* Push mapping.
8712
*/
8713
if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
8714
depth) == NULL)
8715
goto internal_error;
8716
8717
prevns = ns;
8718
next_ns_decl:
8719
ns = ns->next;
8720
}
8721
}
8722
if (! adoptns)
8723
goto ns_end;
8724
/* Falls through. */
8725
case XML_ATTRIBUTE_NODE:
8726
/* No ns, no fun. */
8727
if (cur->ns == NULL)
8728
goto ns_end;
8729
8730
if (! parnsdone) {
8731
if ((elem->parent) &&
8732
((xmlNodePtr) elem->parent->doc != elem->parent)) {
8733
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8734
elem->parent) == -1)
8735
goto internal_error;
8736
}
8737
parnsdone = 1;
8738
}
8739
/*
8740
* Adjust the reference if this was a redundant ns-decl.
8741
*/
8742
if (listRedund) {
8743
for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8744
if (cur->ns == listRedund[j]) {
8745
cur->ns = listRedund[++j];
8746
break;
8747
}
8748
}
8749
}
8750
/*
8751
* Adopt ns-references.
8752
*/
8753
if (XML_NSMAP_NOTEMPTY(nsMap)) {
8754
/*
8755
* Search for a mapping.
8756
*/
8757
XML_NSMAP_FOREACH(nsMap, mi) {
8758
if ((mi->shadowDepth == -1) &&
8759
(cur->ns == mi->oldNs)) {
8760
8761
cur->ns = mi->newNs;
8762
goto ns_end;
8763
}
8764
}
8765
}
8766
/*
8767
* Acquire a normalized ns-decl and add it to the map.
8768
*/
8769
if (xmlDOMWrapNSNormAcquireNormalizedNs(doc, curElem,
8770
cur->ns, &ns,
8771
&nsMap, depth,
8772
ancestorsOnly,
8773
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8774
goto internal_error;
8775
cur->ns = ns;
8776
8777
ns_end:
8778
if ((cur->type == XML_ELEMENT_NODE) &&
8779
(cur->properties != NULL)) {
8780
/*
8781
* Process attributes.
8782
*/
8783
cur = (xmlNodePtr) cur->properties;
8784
continue;
8785
}
8786
break;
8787
default:
8788
goto next_sibling;
8789
}
8790
into_content:
8791
if ((cur->type == XML_ELEMENT_NODE) &&
8792
(cur->children != NULL)) {
8793
/*
8794
* Process content of element-nodes only.
8795
*/
8796
cur = cur->children;
8797
continue;
8798
}
8799
next_sibling:
8800
if (cur == elem)
8801
break;
8802
if (cur->type == XML_ELEMENT_NODE) {
8803
if (XML_NSMAP_NOTEMPTY(nsMap)) {
8804
/*
8805
* Pop mappings.
8806
*/
8807
while ((nsMap->last != NULL) &&
8808
(nsMap->last->depth >= depth))
8809
{
8810
XML_NSMAP_POP(nsMap, mi)
8811
}
8812
/*
8813
* Unshadow.
8814
*/
8815
XML_NSMAP_FOREACH(nsMap, mi) {
8816
if (mi->shadowDepth >= depth)
8817
mi->shadowDepth = -1;
8818
}
8819
}
8820
depth--;
8821
}
8822
if (cur->next != NULL)
8823
cur = cur->next;
8824
else {
8825
if (cur->type == XML_ATTRIBUTE_NODE) {
8826
cur = cur->parent;
8827
goto into_content;
8828
}
8829
cur = cur->parent;
8830
goto next_sibling;
8831
}
8832
} while (cur != NULL);
8833
8834
ret = 0;
8835
goto exit;
8836
internal_error:
8837
ret = -1;
8838
exit:
8839
if (listRedund) {
8840
for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8841
xmlFreeNs(listRedund[j]);
8842
}
8843
xmlFree(listRedund);
8844
}
8845
if (nsMap != NULL)
8846
xmlDOMWrapNsMapFree(nsMap);
8847
return (ret);
8848
}
8849
8850
/*
8851
* xmlDOMWrapAdoptBranch:
8852
* @ctxt: the optional context for custom processing
8853
* @sourceDoc: the optional sourceDoc
8854
* @node: the element-node to start with
8855
* @destDoc: the destination doc for adoption
8856
* @destParent: the optional new parent of @node in @destDoc
8857
* @options: option flags
8858
*
8859
* Ensures that ns-references point to @destDoc: either to
8860
* elements->nsDef entries if @destParent is given, or to
8861
* @destDoc->oldNs otherwise.
8862
* If @destParent is given, it ensures that the tree is namespace
8863
* wellformed by creating additional ns-decls where needed.
8864
* Note that, since prefixes of already existent ns-decls can be
8865
* shadowed by this process, it could break QNames in attribute
8866
* values or element content.
8867
*
8868
* NOTE: This function was not intensively tested.
8869
*
8870
* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8871
*/
8872
static int
8873
xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8874
xmlDocPtr sourceDoc,
8875
xmlNodePtr node,
8876
xmlDocPtr destDoc,
8877
xmlNodePtr destParent,
8878
int options ATTRIBUTE_UNUSED)
8879
{
8880
int ret = 0;
8881
xmlNodePtr cur, curElem = NULL;
8882
xmlNsMapPtr nsMap = NULL;
8883
xmlNsMapItemPtr mi;
8884
xmlNsPtr ns = NULL;
8885
int depth = -1, adoptStr = 1;
8886
/* gather @parent's ns-decls. */
8887
int parnsdone;
8888
/* @ancestorsOnly should be set per option. */
8889
int ancestorsOnly = 0;
8890
8891
/*
8892
* Optimize string adoption for equal or none dicts.
8893
*/
8894
if ((sourceDoc != NULL) &&
8895
(sourceDoc->dict == destDoc->dict))
8896
adoptStr = 0;
8897
else
8898
adoptStr = 1;
8899
8900
/*
8901
* Get the ns-map from the context if available.
8902
*/
8903
if (ctxt)
8904
nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8905
/*
8906
* Disable search for ns-decls in the parent-axis of the
8907
* destination element, if:
8908
* 1) there's no destination parent
8909
* 2) custom ns-reference handling is used
8910
*/
8911
if ((destParent == NULL) ||
8912
(ctxt && ctxt->getNsForNodeFunc))
8913
{
8914
parnsdone = 1;
8915
} else
8916
parnsdone = 0;
8917
8918
cur = node;
8919
if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
8920
goto internal_error;
8921
8922
while (cur != NULL) {
8923
/*
8924
* Paranoid source-doc sanity check.
8925
*/
8926
if (cur->doc != sourceDoc) {
8927
/*
8928
* We'll assume XIncluded nodes if the doc differs.
8929
* TODO: Do we need to reconciliate XIncluded nodes?
8930
* This here skips XIncluded nodes and tries to handle
8931
* broken sequences.
8932
*/
8933
if (cur->next == NULL)
8934
goto leave_node;
8935
do {
8936
cur = cur->next;
8937
if ((cur->type == XML_XINCLUDE_END) ||
8938
(cur->doc == node->doc))
8939
break;
8940
} while (cur->next != NULL);
8941
8942
if (cur->doc != node->doc)
8943
goto leave_node;
8944
}
8945
cur->doc = destDoc;
8946
switch (cur->type) {
8947
case XML_XINCLUDE_START:
8948
case XML_XINCLUDE_END:
8949
/*
8950
* TODO
8951
*/
8952
return (-1);
8953
case XML_ELEMENT_NODE:
8954
curElem = cur;
8955
depth++;
8956
/*
8957
* Namespace declarations.
8958
* - ns->href and ns->prefix are never in the dict, so
8959
* we need not move the values over to the destination dict.
8960
* - Note that for custom handling of ns-references,
8961
* the ns-decls need not be stored in the ns-map,
8962
* since they won't be referenced by node->ns.
8963
*/
8964
if ((cur->nsDef) &&
8965
((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
8966
{
8967
if (! parnsdone) {
8968
/*
8969
* Gather @parent's in-scope ns-decls.
8970
*/
8971
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8972
destParent) == -1)
8973
goto internal_error;
8974
parnsdone = 1;
8975
}
8976
for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8977
/*
8978
* NOTE: ns->prefix and ns->href are never in the dict.
8979
* XML_TREE_ADOPT_STR(ns->prefix)
8980
* XML_TREE_ADOPT_STR(ns->href)
8981
*/
8982
/*
8983
* Does it shadow any ns-decl?
8984
*/
8985
if (XML_NSMAP_NOTEMPTY(nsMap)) {
8986
XML_NSMAP_FOREACH(nsMap, mi) {
8987
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8988
(mi->shadowDepth == -1) &&
8989
((ns->prefix == mi->newNs->prefix) ||
8990
xmlStrEqual(ns->prefix,
8991
mi->newNs->prefix))) {
8992
8993
mi->shadowDepth = depth;
8994
}
8995
}
8996
}
8997
/*
8998
* Push mapping.
8999
*/
9000
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9001
ns, ns, depth) == NULL)
9002
goto internal_error;
9003
}
9004
}
9005
/* Falls through. */
9006
case XML_ATTRIBUTE_NODE:
9007
/* No namespace, no fun. */
9008
if (cur->ns == NULL)
9009
goto ns_end;
9010
9011
if (! parnsdone) {
9012
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9013
destParent) == -1)
9014
goto internal_error;
9015
parnsdone = 1;
9016
}
9017
/*
9018
* Adopt ns-references.
9019
*/
9020
if (XML_NSMAP_NOTEMPTY(nsMap)) {
9021
/*
9022
* Search for a mapping.
9023
*/
9024
XML_NSMAP_FOREACH(nsMap, mi) {
9025
if ((mi->shadowDepth == -1) &&
9026
(cur->ns == mi->oldNs)) {
9027
9028
cur->ns = mi->newNs;
9029
goto ns_end;
9030
}
9031
}
9032
}
9033
/*
9034
* No matching namespace in scope. We need a new one.
9035
*/
9036
if ((ctxt) && (ctxt->getNsForNodeFunc)) {
9037
/*
9038
* User-defined behaviour.
9039
*/
9040
ns = ctxt->getNsForNodeFunc(ctxt, cur,
9041
cur->ns->href, cur->ns->prefix);
9042
/*
9043
* Insert mapping if ns is available; it's the users fault
9044
* if not.
9045
*/
9046
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9047
cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9048
goto internal_error;
9049
cur->ns = ns;
9050
} else {
9051
/*
9052
* Acquire a normalized ns-decl and add it to the map.
9053
*/
9054
if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9055
/* ns-decls on curElem or on destDoc->oldNs */
9056
destParent ? curElem : NULL,
9057
cur->ns, &ns,
9058
&nsMap, depth,
9059
ancestorsOnly,
9060
/* ns-decls must be prefixed for attributes. */
9061
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9062
goto internal_error;
9063
cur->ns = ns;
9064
}
9065
ns_end:
9066
/*
9067
* Further node properties.
9068
* TODO: Is this all?
9069
*/
9070
XML_TREE_ADOPT_STR(cur->name)
9071
if (cur->type == XML_ELEMENT_NODE) {
9072
cur->psvi = NULL;
9073
cur->line = 0;
9074
cur->extra = 0;
9075
/*
9076
* Walk attributes.
9077
*/
9078
if (cur->properties != NULL) {
9079
/*
9080
* Process first attribute node.
9081
*/
9082
cur = (xmlNodePtr) cur->properties;
9083
continue;
9084
}
9085
} else {
9086
/*
9087
* Attributes.
9088
*/
9089
if ((sourceDoc != NULL) &&
9090
(((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
9091
{
9092
xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
9093
}
9094
((xmlAttrPtr) cur)->atype = 0;
9095
((xmlAttrPtr) cur)->psvi = NULL;
9096
}
9097
break;
9098
case XML_TEXT_NODE:
9099
case XML_CDATA_SECTION_NODE:
9100
/*
9101
* This puts the content in the dest dict, only if
9102
* it was previously in the source dict.
9103
*/
9104
XML_TREE_ADOPT_STR_2(cur->content)
9105
goto leave_node;
9106
case XML_ENTITY_REF_NODE:
9107
/*
9108
* Remove reference to the entity-node.
9109
*/
9110
cur->content = NULL;
9111
cur->children = NULL;
9112
cur->last = NULL;
9113
if ((destDoc->intSubset) || (destDoc->extSubset)) {
9114
xmlEntityPtr ent;
9115
/*
9116
* Assign new entity-node if available.
9117
*/
9118
ent = xmlGetDocEntity(destDoc, cur->name);
9119
if (ent != NULL) {
9120
cur->content = ent->content;
9121
cur->children = (xmlNodePtr) ent;
9122
cur->last = (xmlNodePtr) ent;
9123
}
9124
}
9125
goto leave_node;
9126
case XML_PI_NODE:
9127
XML_TREE_ADOPT_STR(cur->name)
9128
XML_TREE_ADOPT_STR_2(cur->content)
9129
break;
9130
case XML_COMMENT_NODE:
9131
break;
9132
default:
9133
goto internal_error;
9134
}
9135
/*
9136
* Walk the tree.
9137
*/
9138
if (cur->children != NULL) {
9139
cur = cur->children;
9140
continue;
9141
}
9142
9143
leave_node:
9144
if (cur == node)
9145
break;
9146
if ((cur->type == XML_ELEMENT_NODE) ||
9147
(cur->type == XML_XINCLUDE_START) ||
9148
(cur->type == XML_XINCLUDE_END))
9149
{
9150
/*
9151
* TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9152
*/
9153
if (XML_NSMAP_NOTEMPTY(nsMap)) {
9154
/*
9155
* Pop mappings.
9156
*/
9157
while ((nsMap->last != NULL) &&
9158
(nsMap->last->depth >= depth))
9159
{
9160
XML_NSMAP_POP(nsMap, mi)
9161
}
9162
/*
9163
* Unshadow.
9164
*/
9165
XML_NSMAP_FOREACH(nsMap, mi) {
9166
if (mi->shadowDepth >= depth)
9167
mi->shadowDepth = -1;
9168
}
9169
}
9170
depth--;
9171
}
9172
if (cur->next != NULL)
9173
cur = cur->next;
9174
else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9175
(cur->parent->children != NULL))
9176
{
9177
cur = cur->parent->children;
9178
} else {
9179
cur = cur->parent;
9180
goto leave_node;
9181
}
9182
}
9183
9184
goto exit;
9185
9186
internal_error:
9187
ret = -1;
9188
9189
exit:
9190
/*
9191
* Cleanup.
9192
*/
9193
if (nsMap != NULL) {
9194
if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9195
/*
9196
* Just cleanup the map but don't free.
9197
*/
9198
if (nsMap->first) {
9199
if (nsMap->pool)
9200
nsMap->last->next = nsMap->pool;
9201
nsMap->pool = nsMap->first;
9202
nsMap->first = NULL;
9203
}
9204
} else
9205
xmlDOMWrapNsMapFree(nsMap);
9206
}
9207
return(ret);
9208
}
9209
9210
/*
9211
* xmlDOMWrapCloneNode:
9212
* @ctxt: the optional context for custom processing
9213
* @sourceDoc: the optional sourceDoc
9214
* @node: the node to start with
9215
* @resNode: the clone of the given @node
9216
* @destDoc: the destination doc
9217
* @destParent: the optional new parent of @node in @destDoc
9218
* @deep: descend into child if set
9219
* @options: option flags
9220
*
9221
* References of out-of scope ns-decls are remapped to point to @destDoc:
9222
* 1) If @destParent is given, then nsDef entries on element-nodes are used
9223
* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9224
* This is the case when you don't know already where the cloned branch
9225
* will be added to.
9226
*
9227
* If @destParent is given, it ensures that the tree is namespace
9228
* wellformed by creating additional ns-decls where needed.
9229
* Note that, since prefixes of already existent ns-decls can be
9230
* shadowed by this process, it could break QNames in attribute
9231
* values or element content.
9232
* TODO:
9233
* 1) What to do with XInclude? Currently this returns an error for XInclude.
9234
*
9235
* Returns 0 if the operation succeeded,
9236
* 1 if a node of unsupported (or not yet supported) type was given,
9237
* -1 on API/internal errors.
9238
*/
9239
9240
int
9241
xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9242
xmlDocPtr sourceDoc,
9243
xmlNodePtr node,
9244
xmlNodePtr *resNode,
9245
xmlDocPtr destDoc,
9246
xmlNodePtr destParent,
9247
int deep,
9248
int options ATTRIBUTE_UNUSED)
9249
{
9250
int ret = 0;
9251
xmlNodePtr cur, curElem = NULL;
9252
xmlNsMapPtr nsMap = NULL;
9253
xmlNsMapItemPtr mi;
9254
xmlNsPtr ns;
9255
int depth = -1;
9256
/* int adoptStr = 1; */
9257
/* gather @parent's ns-decls. */
9258
int parnsdone = 0;
9259
/*
9260
* @ancestorsOnly:
9261
* TODO: @ancestorsOnly should be set per option.
9262
*
9263
*/
9264
int ancestorsOnly = 0;
9265
xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
9266
xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9267
xmlDictPtr dict; /* The destination dict */
9268
9269
if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
9270
return(-1);
9271
/*
9272
* TODO: Initially we support only element-nodes.
9273
*/
9274
if (node->type != XML_ELEMENT_NODE)
9275
return(1);
9276
/*
9277
* Check node->doc sanity.
9278
*/
9279
if ((node->doc != NULL) && (sourceDoc != NULL) &&
9280
(node->doc != sourceDoc)) {
9281
/*
9282
* Might be an XIncluded node.
9283
*/
9284
return (-1);
9285
}
9286
if (sourceDoc == NULL)
9287
sourceDoc = node->doc;
9288
if (sourceDoc == NULL)
9289
return (-1);
9290
9291
dict = destDoc->dict;
9292
/*
9293
* Reuse the namespace map of the context.
9294
*/
9295
if (ctxt)
9296
nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9297
9298
*resNode = NULL;
9299
9300
cur = node;
9301
if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9302
return(-1);
9303
9304
while (cur != NULL) {
9305
if (cur->doc != sourceDoc) {
9306
/*
9307
* We'll assume XIncluded nodes if the doc differs.
9308
* TODO: Do we need to reconciliate XIncluded nodes?
9309
* TODO: This here returns -1 in this case.
9310
*/
9311
goto internal_error;
9312
}
9313
/*
9314
* Create a new node.
9315
*/
9316
switch (cur->type) {
9317
case XML_XINCLUDE_START:
9318
case XML_XINCLUDE_END:
9319
/*
9320
* TODO: What to do with XInclude?
9321
*/
9322
goto internal_error;
9323
break;
9324
case XML_ELEMENT_NODE:
9325
case XML_TEXT_NODE:
9326
case XML_CDATA_SECTION_NODE:
9327
case XML_COMMENT_NODE:
9328
case XML_PI_NODE:
9329
case XML_DOCUMENT_FRAG_NODE:
9330
case XML_ENTITY_REF_NODE:
9331
case XML_ENTITY_NODE:
9332
/*
9333
* Nodes of xmlNode structure.
9334
*/
9335
clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9336
if (clone == NULL) {
9337
xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
9338
goto internal_error;
9339
}
9340
memset(clone, 0, sizeof(xmlNode));
9341
/*
9342
* Set hierarchical links.
9343
*/
9344
if (resultClone != NULL) {
9345
clone->parent = parentClone;
9346
if (prevClone) {
9347
prevClone->next = clone;
9348
clone->prev = prevClone;
9349
} else
9350
parentClone->children = clone;
9351
} else
9352
resultClone = clone;
9353
9354
break;
9355
case XML_ATTRIBUTE_NODE:
9356
/*
9357
* Attributes (xmlAttr).
9358
*/
9359
/* Use xmlRealloc to avoid -Warray-bounds warning */
9360
clone = (xmlNodePtr) xmlRealloc(NULL, sizeof(xmlAttr));
9361
if (clone == NULL) {
9362
xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
9363
goto internal_error;
9364
}
9365
memset(clone, 0, sizeof(xmlAttr));
9366
/*
9367
* Set hierarchical links.
9368
* TODO: Change this to add to the end of attributes.
9369
*/
9370
if (resultClone != NULL) {
9371
clone->parent = parentClone;
9372
if (prevClone) {
9373
prevClone->next = clone;
9374
clone->prev = prevClone;
9375
} else
9376
parentClone->properties = (xmlAttrPtr) clone;
9377
} else
9378
resultClone = clone;
9379
break;
9380
default:
9381
/*
9382
* TODO QUESTION: Any other nodes expected?
9383
*/
9384
goto internal_error;
9385
}
9386
9387
clone->type = cur->type;
9388
clone->doc = destDoc;
9389
9390
/*
9391
* Clone the name of the node if any.
9392
*/
9393
if (cur->name == xmlStringText)
9394
clone->name = xmlStringText;
9395
else if (cur->name == xmlStringTextNoenc)
9396
/*
9397
* NOTE: Although xmlStringTextNoenc is never assigned to a node
9398
* in tree.c, it might be set in Libxslt via
9399
* "xsl:disable-output-escaping".
9400
*/
9401
clone->name = xmlStringTextNoenc;
9402
else if (cur->name == xmlStringComment)
9403
clone->name = xmlStringComment;
9404
else if (cur->name != NULL) {
9405
DICT_CONST_COPY(cur->name, clone->name);
9406
}
9407
9408
switch (cur->type) {
9409
case XML_XINCLUDE_START:
9410
case XML_XINCLUDE_END:
9411
/*
9412
* TODO
9413
*/
9414
return (-1);
9415
case XML_ELEMENT_NODE:
9416
curElem = cur;
9417
depth++;
9418
/*
9419
* Namespace declarations.
9420
*/
9421
if (cur->nsDef != NULL) {
9422
if (! parnsdone) {
9423
if (destParent && (ctxt == NULL)) {
9424
/*
9425
* Gather @parent's in-scope ns-decls.
9426
*/
9427
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9428
destParent) == -1)
9429
goto internal_error;
9430
}
9431
parnsdone = 1;
9432
}
9433
/*
9434
* Clone namespace declarations.
9435
*/
9436
cloneNsDefSlot = &(clone->nsDef);
9437
for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9438
/*
9439
* Create a new xmlNs.
9440
*/
9441
cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9442
if (cloneNs == NULL) {
9443
xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
9444
"allocating namespace");
9445
return(-1);
9446
}
9447
memset(cloneNs, 0, sizeof(xmlNs));
9448
cloneNs->type = XML_LOCAL_NAMESPACE;
9449
9450
if (ns->href != NULL)
9451
cloneNs->href = xmlStrdup(ns->href);
9452
if (ns->prefix != NULL)
9453
cloneNs->prefix = xmlStrdup(ns->prefix);
9454
9455
*cloneNsDefSlot = cloneNs;
9456
cloneNsDefSlot = &(cloneNs->next);
9457
9458
/*
9459
* Note that for custom handling of ns-references,
9460
* the ns-decls need not be stored in the ns-map,
9461
* since they won't be referenced by node->ns.
9462
*/
9463
if ((ctxt == NULL) ||
9464
(ctxt->getNsForNodeFunc == NULL))
9465
{
9466
/*
9467
* Does it shadow any ns-decl?
9468
*/
9469
if (XML_NSMAP_NOTEMPTY(nsMap)) {
9470
XML_NSMAP_FOREACH(nsMap, mi) {
9471
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9472
(mi->shadowDepth == -1) &&
9473
((ns->prefix == mi->newNs->prefix) ||
9474
xmlStrEqual(ns->prefix,
9475
mi->newNs->prefix))) {
9476
/*
9477
* Mark as shadowed at the current
9478
* depth.
9479
*/
9480
mi->shadowDepth = depth;
9481
}
9482
}
9483
}
9484
/*
9485
* Push mapping.
9486
*/
9487
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9488
ns, cloneNs, depth) == NULL)
9489
goto internal_error;
9490
}
9491
}
9492
}
9493
/* cur->ns will be processed further down. */
9494
break;
9495
case XML_ATTRIBUTE_NODE:
9496
/* IDs will be processed further down. */
9497
/* cur->ns will be processed further down. */
9498
break;
9499
case XML_TEXT_NODE:
9500
case XML_CDATA_SECTION_NODE:
9501
/*
9502
* Note that this will also cover the values of attributes.
9503
*/
9504
DICT_COPY(cur->content, clone->content);
9505
goto leave_node;
9506
case XML_ENTITY_NODE:
9507
/* TODO: What to do here? */
9508
goto leave_node;
9509
case XML_ENTITY_REF_NODE:
9510
if (sourceDoc != destDoc) {
9511
if ((destDoc->intSubset) || (destDoc->extSubset)) {
9512
xmlEntityPtr ent;
9513
/*
9514
* Different doc: Assign new entity-node if available.
9515
*/
9516
ent = xmlGetDocEntity(destDoc, cur->name);
9517
if (ent != NULL) {
9518
clone->content = ent->content;
9519
clone->children = (xmlNodePtr) ent;
9520
clone->last = (xmlNodePtr) ent;
9521
}
9522
}
9523
} else {
9524
/*
9525
* Same doc: Use the current node's entity declaration
9526
* and value.
9527
*/
9528
clone->content = cur->content;
9529
clone->children = cur->children;
9530
clone->last = cur->last;
9531
}
9532
goto leave_node;
9533
case XML_PI_NODE:
9534
DICT_COPY(cur->content, clone->content);
9535
goto leave_node;
9536
case XML_COMMENT_NODE:
9537
DICT_COPY(cur->content, clone->content);
9538
goto leave_node;
9539
default:
9540
goto internal_error;
9541
}
9542
9543
if (cur->ns == NULL)
9544
goto end_ns_reference;
9545
9546
/* handle_ns_reference: */
9547
/*
9548
** The following will take care of references to ns-decls ********
9549
** and is intended only for element- and attribute-nodes.
9550
**
9551
*/
9552
if (! parnsdone) {
9553
if (destParent && (ctxt == NULL)) {
9554
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
9555
goto internal_error;
9556
}
9557
parnsdone = 1;
9558
}
9559
/*
9560
* Adopt ns-references.
9561
*/
9562
if (XML_NSMAP_NOTEMPTY(nsMap)) {
9563
/*
9564
* Search for a mapping.
9565
*/
9566
XML_NSMAP_FOREACH(nsMap, mi) {
9567
if ((mi->shadowDepth == -1) &&
9568
(cur->ns == mi->oldNs)) {
9569
/*
9570
* This is the nice case: a mapping was found.
9571
*/
9572
clone->ns = mi->newNs;
9573
goto end_ns_reference;
9574
}
9575
}
9576
}
9577
/*
9578
* No matching namespace in scope. We need a new one.
9579
*/
9580
if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
9581
/*
9582
* User-defined behaviour.
9583
*/
9584
ns = ctxt->getNsForNodeFunc(ctxt, cur,
9585
cur->ns->href, cur->ns->prefix);
9586
/*
9587
* Add user's mapping.
9588
*/
9589
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9590
cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9591
goto internal_error;
9592
clone->ns = ns;
9593
} else {
9594
/*
9595
* Acquire a normalized ns-decl and add it to the map.
9596
*/
9597
if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9598
/* ns-decls on curElem or on destDoc->oldNs */
9599
destParent ? curElem : NULL,
9600
cur->ns, &ns,
9601
&nsMap, depth,
9602
/* if we need to search only in the ancestor-axis */
9603
ancestorsOnly,
9604
/* ns-decls must be prefixed for attributes. */
9605
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9606
goto internal_error;
9607
clone->ns = ns;
9608
}
9609
9610
end_ns_reference:
9611
9612
/*
9613
* Some post-processing.
9614
*
9615
* Handle ID attributes.
9616
*/
9617
if ((clone->type == XML_ATTRIBUTE_NODE) &&
9618
(clone->parent != NULL))
9619
{
9620
if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9621
9622
xmlChar *idVal;
9623
9624
idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9625
if (idVal != NULL) {
9626
if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9627
/* TODO: error message. */
9628
xmlFree(idVal);
9629
goto internal_error;
9630
}
9631
xmlFree(idVal);
9632
}
9633
}
9634
}
9635
/*
9636
**
9637
** The following will traverse the tree **************************
9638
**
9639
*
9640
* Walk the element's attributes before descending into child-nodes.
9641
*/
9642
if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9643
prevClone = NULL;
9644
parentClone = clone;
9645
cur = (xmlNodePtr) cur->properties;
9646
continue;
9647
}
9648
into_content:
9649
/*
9650
* Descend into child-nodes.
9651
*/
9652
if (cur->children != NULL) {
9653
if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9654
prevClone = NULL;
9655
parentClone = clone;
9656
cur = cur->children;
9657
continue;
9658
}
9659
}
9660
9661
leave_node:
9662
/*
9663
* At this point we are done with the node, its content
9664
* and an element-nodes's attribute-nodes.
9665
*/
9666
if (cur == node)
9667
break;
9668
if ((cur->type == XML_ELEMENT_NODE) ||
9669
(cur->type == XML_XINCLUDE_START) ||
9670
(cur->type == XML_XINCLUDE_END)) {
9671
/*
9672
* TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9673
*/
9674
if (XML_NSMAP_NOTEMPTY(nsMap)) {
9675
/*
9676
* Pop mappings.
9677
*/
9678
while ((nsMap->last != NULL) &&
9679
(nsMap->last->depth >= depth))
9680
{
9681
XML_NSMAP_POP(nsMap, mi)
9682
}
9683
/*
9684
* Unshadow.
9685
*/
9686
XML_NSMAP_FOREACH(nsMap, mi) {
9687
if (mi->shadowDepth >= depth)
9688
mi->shadowDepth = -1;
9689
}
9690
}
9691
depth--;
9692
}
9693
if (cur->next != NULL) {
9694
prevClone = clone;
9695
cur = cur->next;
9696
} else if (cur->type != XML_ATTRIBUTE_NODE) {
9697
/*
9698
* Set clone->last.
9699
*/
9700
if (clone->parent != NULL)
9701
clone->parent->last = clone;
9702
clone = clone->parent;
9703
if (clone != NULL)
9704
parentClone = clone->parent;
9705
/*
9706
* Process parent --> next;
9707
*/
9708
cur = cur->parent;
9709
goto leave_node;
9710
} else {
9711
/* This is for attributes only. */
9712
clone = clone->parent;
9713
parentClone = clone->parent;
9714
/*
9715
* Process parent-element --> children.
9716
*/
9717
cur = cur->parent;
9718
goto into_content;
9719
}
9720
}
9721
goto exit;
9722
9723
internal_error:
9724
ret = -1;
9725
9726
exit:
9727
/*
9728
* Cleanup.
9729
*/
9730
if (nsMap != NULL) {
9731
if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9732
/*
9733
* Just cleanup the map but don't free.
9734
*/
9735
if (nsMap->first) {
9736
if (nsMap->pool)
9737
nsMap->last->next = nsMap->pool;
9738
nsMap->pool = nsMap->first;
9739
nsMap->first = NULL;
9740
}
9741
} else
9742
xmlDOMWrapNsMapFree(nsMap);
9743
}
9744
/*
9745
* TODO: Should we try a cleanup of the cloned node in case of a
9746
* fatal error?
9747
*/
9748
*resNode = resultClone;
9749
return (ret);
9750
}
9751
9752
/*
9753
* xmlDOMWrapAdoptAttr:
9754
* @ctxt: the optional context for custom processing
9755
* @sourceDoc: the optional source document of attr
9756
* @attr: the attribute-node to be adopted
9757
* @destDoc: the destination doc for adoption
9758
* @destParent: the optional new parent of @attr in @destDoc
9759
* @options: option flags
9760
*
9761
* @attr is adopted by @destDoc.
9762
* Ensures that ns-references point to @destDoc: either to
9763
* elements->nsDef entries if @destParent is given, or to
9764
* @destDoc->oldNs otherwise.
9765
*
9766
* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9767
*/
9768
static int
9769
xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9770
xmlDocPtr sourceDoc,
9771
xmlAttrPtr attr,
9772
xmlDocPtr destDoc,
9773
xmlNodePtr destParent,
9774
int options ATTRIBUTE_UNUSED)
9775
{
9776
xmlNodePtr cur;
9777
int adoptStr = 1;
9778
9779
if ((attr == NULL) || (destDoc == NULL))
9780
return (-1);
9781
9782
attr->doc = destDoc;
9783
if (attr->ns != NULL) {
9784
xmlNsPtr ns = NULL;
9785
9786
if (ctxt != NULL) {
9787
/* TODO: User defined. */
9788
}
9789
/* XML Namespace. */
9790
if (IS_STR_XML(attr->ns->prefix)) {
9791
ns = xmlTreeEnsureXMLDecl(destDoc);
9792
} else if (destParent == NULL) {
9793
/*
9794
* Store in @destDoc->oldNs.
9795
*/
9796
ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9797
} else {
9798
/*
9799
* Declare on @destParent.
9800
*/
9801
if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
9802
&ns, 1) == -1)
9803
goto internal_error;
9804
if (ns == NULL) {
9805
ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9806
attr->ns->href, attr->ns->prefix, 1);
9807
}
9808
}
9809
if (ns == NULL)
9810
goto internal_error;
9811
attr->ns = ns;
9812
}
9813
9814
XML_TREE_ADOPT_STR(attr->name);
9815
attr->atype = 0;
9816
attr->psvi = NULL;
9817
/*
9818
* Walk content.
9819
*/
9820
if (attr->children == NULL)
9821
return (0);
9822
cur = attr->children;
9823
if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9824
goto internal_error;
9825
while (cur != NULL) {
9826
cur->doc = destDoc;
9827
switch (cur->type) {
9828
case XML_TEXT_NODE:
9829
case XML_CDATA_SECTION_NODE:
9830
XML_TREE_ADOPT_STR_2(cur->content)
9831
break;
9832
case XML_ENTITY_REF_NODE:
9833
/*
9834
* Remove reference to the entity-node.
9835
*/
9836
cur->content = NULL;
9837
cur->children = NULL;
9838
cur->last = NULL;
9839
if ((destDoc->intSubset) || (destDoc->extSubset)) {
9840
xmlEntityPtr ent;
9841
/*
9842
* Assign new entity-node if available.
9843
*/
9844
ent = xmlGetDocEntity(destDoc, cur->name);
9845
if (ent != NULL) {
9846
cur->content = ent->content;
9847
cur->children = (xmlNodePtr) ent;
9848
cur->last = (xmlNodePtr) ent;
9849
}
9850
}
9851
break;
9852
default:
9853
break;
9854
}
9855
if (cur->children != NULL) {
9856
cur = cur->children;
9857
continue;
9858
}
9859
next_sibling:
9860
if (cur == (xmlNodePtr) attr)
9861
break;
9862
if (cur->next != NULL)
9863
cur = cur->next;
9864
else {
9865
cur = cur->parent;
9866
goto next_sibling;
9867
}
9868
}
9869
return (0);
9870
internal_error:
9871
return (-1);
9872
}
9873
9874
/*
9875
* xmlDOMWrapAdoptNode:
9876
* @ctxt: the optional context for custom processing
9877
* @sourceDoc: the optional sourceDoc
9878
* @node: the node to start with
9879
* @destDoc: the destination doc
9880
* @destParent: the optional new parent of @node in @destDoc
9881
* @options: option flags
9882
*
9883
* References of out-of scope ns-decls are remapped to point to @destDoc:
9884
* 1) If @destParent is given, then nsDef entries on element-nodes are used
9885
* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9886
* This is the case when you have an unlinked node and just want to move it
9887
* to the context of
9888
*
9889
* If @destParent is given, it ensures that the tree is namespace
9890
* wellformed by creating additional ns-decls where needed.
9891
* Note that, since prefixes of already existent ns-decls can be
9892
* shadowed by this process, it could break QNames in attribute
9893
* values or element content.
9894
* NOTE: This function was not intensively tested.
9895
*
9896
* Returns 0 if the operation succeeded,
9897
* 1 if a node of unsupported type was given,
9898
* 2 if a node of not yet supported type was given and
9899
* -1 on API/internal errors.
9900
*/
9901
int
9902
xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9903
xmlDocPtr sourceDoc,
9904
xmlNodePtr node,
9905
xmlDocPtr destDoc,
9906
xmlNodePtr destParent,
9907
int options)
9908
{
9909
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
9910
(destDoc == NULL) ||
9911
((destParent != NULL) && (destParent->doc != destDoc)))
9912
return(-1);
9913
/*
9914
* Check node->doc sanity.
9915
*/
9916
if ((node->doc != NULL) && (sourceDoc != NULL) &&
9917
(node->doc != sourceDoc)) {
9918
/*
9919
* Might be an XIncluded node.
9920
*/
9921
return (-1);
9922
}
9923
if (sourceDoc == NULL)
9924
sourceDoc = node->doc;
9925
if (sourceDoc == destDoc)
9926
return (-1);
9927
switch (node->type) {
9928
case XML_ELEMENT_NODE:
9929
case XML_ATTRIBUTE_NODE:
9930
case XML_TEXT_NODE:
9931
case XML_CDATA_SECTION_NODE:
9932
case XML_ENTITY_REF_NODE:
9933
case XML_PI_NODE:
9934
case XML_COMMENT_NODE:
9935
break;
9936
case XML_DOCUMENT_FRAG_NODE:
9937
/* TODO: Support document-fragment-nodes. */
9938
return (2);
9939
default:
9940
return (1);
9941
}
9942
/*
9943
* Unlink only if @node was not already added to @destParent.
9944
*/
9945
if ((node->parent != NULL) && (destParent != node->parent))
9946
xmlUnlinkNode(node);
9947
9948
if (node->type == XML_ELEMENT_NODE) {
9949
return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9950
destDoc, destParent, options));
9951
} else if (node->type == XML_ATTRIBUTE_NODE) {
9952
return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9953
(xmlAttrPtr) node, destDoc, destParent, options));
9954
} else {
9955
xmlNodePtr cur = node;
9956
int adoptStr = 1;
9957
9958
cur->doc = destDoc;
9959
/*
9960
* Optimize string adoption.
9961
*/
9962
if ((sourceDoc != NULL) &&
9963
(sourceDoc->dict == destDoc->dict))
9964
adoptStr = 0;
9965
switch (node->type) {
9966
case XML_TEXT_NODE:
9967
case XML_CDATA_SECTION_NODE:
9968
XML_TREE_ADOPT_STR_2(node->content)
9969
break;
9970
case XML_ENTITY_REF_NODE:
9971
/*
9972
* Remove reference to the entity-node.
9973
*/
9974
node->content = NULL;
9975
node->children = NULL;
9976
node->last = NULL;
9977
if ((destDoc->intSubset) || (destDoc->extSubset)) {
9978
xmlEntityPtr ent;
9979
/*
9980
* Assign new entity-node if available.
9981
*/
9982
ent = xmlGetDocEntity(destDoc, node->name);
9983
if (ent != NULL) {
9984
node->content = ent->content;
9985
node->children = (xmlNodePtr) ent;
9986
node->last = (xmlNodePtr) ent;
9987
}
9988
}
9989
XML_TREE_ADOPT_STR(node->name)
9990
break;
9991
case XML_PI_NODE: {
9992
XML_TREE_ADOPT_STR(node->name)
9993
XML_TREE_ADOPT_STR_2(node->content)
9994
break;
9995
}
9996
default:
9997
break;
9998
}
9999
}
10000
return (0);
10001
}
10002
10003
/************************************************************************
10004
* *
10005
* XHTML detection *
10006
* *
10007
************************************************************************/
10008
10009
#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
10010
"-//W3C//DTD XHTML 1.0 Strict//EN"
10011
#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
10012
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
10013
#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
10014
"-//W3C//DTD XHTML 1.0 Frameset//EN"
10015
#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
10016
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
10017
#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
10018
"-//W3C//DTD XHTML 1.0 Transitional//EN"
10019
#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
10020
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
10021
10022
/**
10023
* xmlIsXHTML:
10024
* @systemID: the system identifier
10025
* @publicID: the public identifier
10026
*
10027
* Try to find if the document correspond to an XHTML DTD
10028
*
10029
* Returns 1 if true, 0 if not and -1 in case of error
10030
*/
10031
int
10032
xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
10033
if ((systemID == NULL) && (publicID == NULL))
10034
return(-1);
10035
if (publicID != NULL) {
10036
if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
10037
if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
10038
if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
10039
}
10040
if (systemID != NULL) {
10041
if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
10042
if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
10043
if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
10044
}
10045
return(0);
10046
}
10047
10048
/************************************************************************
10049
* *
10050
* Node callbacks *
10051
* *
10052
************************************************************************/
10053
10054
/**
10055
* xmlRegisterNodeDefault:
10056
* @func: function pointer to the new RegisterNodeFunc
10057
*
10058
* Registers a callback for node creation
10059
*
10060
* Returns the old value of the registration function
10061
*/
10062
xmlRegisterNodeFunc
10063
xmlRegisterNodeDefault(xmlRegisterNodeFunc func)
10064
{
10065
xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue;
10066
10067
__xmlRegisterCallbacks = 1;
10068
xmlRegisterNodeDefaultValue = func;
10069
return(old);
10070
}
10071
10072
/**
10073
* xmlDeregisterNodeDefault:
10074
* @func: function pointer to the new DeregisterNodeFunc
10075
*
10076
* Registers a callback for node destruction
10077
*
10078
* Returns the previous value of the deregistration function
10079
*/
10080
xmlDeregisterNodeFunc
10081
xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func)
10082
{
10083
xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue;
10084
10085
__xmlRegisterCallbacks = 1;
10086
xmlDeregisterNodeDefaultValue = func;
10087
return(old);
10088
}
10089
10090