1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25
26 /*
27 * class DOMNode
28 *
29 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1950641247
30 * Since:
31 */
32
33 /* {{{ nodeName string
34 readonly=yes
35 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68D095
36 Since:
37 */
dom_node_node_name_read(dom_object * obj,zval * retval)38 int dom_node_node_name_read(dom_object *obj, zval *retval)
39 {
40 xmlNode *nodep;
41 xmlNsPtr ns;
42 char *str = NULL;
43 xmlChar *qname = NULL;
44
45 nodep = dom_object_get_node(obj);
46
47 if (nodep == NULL) {
48 php_dom_throw_error(INVALID_STATE_ERR, 0);
49 return FAILURE;
50 }
51
52 switch (nodep->type) {
53 case XML_ATTRIBUTE_NODE:
54 case XML_ELEMENT_NODE:
55 ns = nodep->ns;
56 if (ns != NULL && ns->prefix) {
57 qname = xmlStrdup(ns->prefix);
58 qname = xmlStrcat(qname, (xmlChar *) ":");
59 qname = xmlStrcat(qname, nodep->name);
60 str = (char *) qname;
61 } else {
62 str = (char *) nodep->name;
63 }
64 break;
65 case XML_NAMESPACE_DECL:
66 ns = nodep->ns;
67 if (ns != NULL && ns->prefix) {
68 qname = xmlStrdup((xmlChar *) "xmlns");
69 qname = xmlStrcat(qname, (xmlChar *) ":");
70 qname = xmlStrcat(qname, nodep->name);
71 str = (char *) qname;
72 } else {
73 str = (char *) nodep->name;
74 }
75 break;
76 case XML_DOCUMENT_TYPE_NODE:
77 case XML_DTD_NODE:
78 case XML_PI_NODE:
79 case XML_ENTITY_DECL:
80 case XML_ENTITY_REF_NODE:
81 case XML_NOTATION_NODE:
82 str = (char *) nodep->name;
83 break;
84 case XML_CDATA_SECTION_NODE:
85 str = "#cdata-section";
86 break;
87 case XML_COMMENT_NODE:
88 str = "#comment";
89 break;
90 case XML_HTML_DOCUMENT_NODE:
91 case XML_DOCUMENT_NODE:
92 str = "#document";
93 break;
94 case XML_DOCUMENT_FRAG_NODE:
95 str = "#document-fragment";
96 break;
97 case XML_TEXT_NODE:
98 str = "#text";
99 break;
100 EMPTY_SWITCH_DEFAULT_CASE();
101 }
102
103 if (str != NULL) {
104 ZVAL_STRING(retval, str);
105 } else {
106 ZVAL_EMPTY_STRING(retval);
107 }
108
109 if (qname != NULL) {
110 xmlFree(qname);
111 }
112
113 return SUCCESS;
114
115 }
116
117 /* }}} */
118
119 /* {{{ nodeValue string
120 readonly=no
121 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68D080
122 Since:
123 */
dom_node_node_value_read(dom_object * obj,zval * retval)124 int dom_node_node_value_read(dom_object *obj, zval *retval)
125 {
126 xmlNode *nodep = dom_object_get_node(obj);
127 char *str = NULL;
128
129 if (nodep == NULL) {
130 php_dom_throw_error(INVALID_STATE_ERR, 0);
131 return FAILURE;
132 }
133
134 /* Access to Element node is implemented as a convenience method */
135 switch (nodep->type) {
136 case XML_ATTRIBUTE_NODE:
137 case XML_TEXT_NODE:
138 case XML_ELEMENT_NODE:
139 case XML_COMMENT_NODE:
140 case XML_CDATA_SECTION_NODE:
141 case XML_PI_NODE:
142 str = (char *) xmlNodeGetContent(nodep);
143 break;
144 case XML_NAMESPACE_DECL:
145 str = (char *) xmlNodeGetContent(nodep->children);
146 break;
147 default:
148 str = NULL;
149 break;
150 }
151
152 if(str != NULL) {
153 ZVAL_STRING(retval, str);
154 xmlFree(str);
155 } else {
156 ZVAL_NULL(retval);
157 }
158
159 return SUCCESS;
160
161 }
162
dom_node_node_value_write(dom_object * obj,zval * newval)163 int dom_node_node_value_write(dom_object *obj, zval *newval)
164 {
165 xmlNode *nodep = dom_object_get_node(obj);
166 zend_string *str;
167
168 if (nodep == NULL) {
169 php_dom_throw_error(INVALID_STATE_ERR, 0);
170 return FAILURE;
171 }
172
173 str = zval_try_get_string(newval);
174 if (UNEXPECTED(!str)) {
175 return FAILURE;
176 }
177
178 /* Access to Element node is implemented as a convenience method */
179 switch (nodep->type) {
180 case XML_ELEMENT_NODE:
181 case XML_ATTRIBUTE_NODE:
182 if (nodep->children) {
183 node_list_unlink(nodep->children);
184 php_libxml_node_free_list((xmlNodePtr) nodep->children);
185 nodep->children = NULL;
186 }
187 case XML_TEXT_NODE:
188 case XML_COMMENT_NODE:
189 case XML_CDATA_SECTION_NODE:
190 case XML_PI_NODE:
191 xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1);
192 break;
193 default:
194 break;
195 }
196
197 zend_string_release_ex(str, 0);
198 return SUCCESS;
199 }
200
201 /* }}} */
202
203 /* {{{ nodeType int
204 readonly=yes
205 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-111237558
206 Since:
207 */
dom_node_node_type_read(dom_object * obj,zval * retval)208 int dom_node_node_type_read(dom_object *obj, zval *retval)
209 {
210 xmlNode *nodep;
211
212 nodep = dom_object_get_node(obj);
213
214 if (nodep == NULL) {
215 php_dom_throw_error(INVALID_STATE_ERR, 0);
216 return FAILURE;
217 }
218
219 /* Specs dictate that they are both type XML_DOCUMENT_TYPE_NODE */
220 if (nodep->type == XML_DTD_NODE) {
221 ZVAL_LONG(retval, XML_DOCUMENT_TYPE_NODE);
222 } else {
223 ZVAL_LONG(retval, nodep->type);
224 }
225
226 return SUCCESS;
227 }
228
229 /* }}} */
230
231 /* {{{ parentNode DomNode
232 readonly=yes
233 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1060184317
234 Since:
235 */
dom_node_parent_node_read(dom_object * obj,zval * retval)236 int dom_node_parent_node_read(dom_object *obj, zval *retval)
237 {
238 xmlNode *nodep, *nodeparent;
239
240 nodep = dom_object_get_node(obj);
241
242 if (nodep == NULL) {
243 php_dom_throw_error(INVALID_STATE_ERR, 0);
244 return FAILURE;
245 }
246
247 nodeparent = nodep->parent;
248 if (!nodeparent) {
249 ZVAL_NULL(retval);
250 return SUCCESS;
251 }
252
253 php_dom_create_object(nodeparent, retval, obj);
254 return SUCCESS;
255 }
256
257 /* }}} */
258
259 /* {{{ childNodes DomNodeList
260 readonly=yes
261 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1451460987
262 Since:
263 */
dom_node_child_nodes_read(dom_object * obj,zval * retval)264 int dom_node_child_nodes_read(dom_object *obj, zval *retval)
265 {
266 xmlNode *nodep = dom_object_get_node(obj);
267 dom_object *intern;
268
269 if (nodep == NULL) {
270 php_dom_throw_error(INVALID_STATE_ERR, 0);
271 return FAILURE;
272 }
273
274 php_dom_create_iterator(retval, DOM_NODELIST);
275 intern = Z_DOMOBJ_P(retval);
276 dom_namednode_iter(obj, XML_ELEMENT_NODE, intern, NULL, NULL, NULL);
277
278 return SUCCESS;
279 }
280 /* }}} */
281
282 /* {{{ firstChild DomNode
283 readonly=yes
284 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-169727388
285 Since:
286 */
dom_node_first_child_read(dom_object * obj,zval * retval)287 int dom_node_first_child_read(dom_object *obj, zval *retval)
288 {
289 xmlNode *nodep, *first = NULL;
290
291 nodep = dom_object_get_node(obj);
292
293 if (nodep == NULL) {
294 php_dom_throw_error(INVALID_STATE_ERR, 0);
295 return FAILURE;
296 }
297
298 if (dom_node_children_valid(nodep) == SUCCESS) {
299 first = nodep->children;
300 }
301
302 if (!first) {
303 ZVAL_NULL(retval);
304 return SUCCESS;
305 }
306
307 php_dom_create_object(first, retval, obj);
308 return SUCCESS;
309 }
310
311 /* }}} */
312
313 /* {{{ lastChild DomNode
314 readonly=yes
315 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-61AD09FB
316 Since:
317 */
dom_node_last_child_read(dom_object * obj,zval * retval)318 int dom_node_last_child_read(dom_object *obj, zval *retval)
319 {
320 xmlNode *nodep, *last = NULL;
321
322 nodep = dom_object_get_node(obj);
323
324 if (nodep == NULL) {
325 php_dom_throw_error(INVALID_STATE_ERR, 0);
326 return FAILURE;
327 }
328
329 if (dom_node_children_valid(nodep) == SUCCESS) {
330 last = nodep->last;
331 }
332
333 if (!last) {
334 ZVAL_NULL(retval);
335 return SUCCESS;
336 }
337
338 php_dom_create_object(last, retval, obj);
339 return SUCCESS;
340 }
341
342 /* }}} */
343
344 /* {{{ previousSibling DomNode
345 readonly=yes
346 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-640FB3C8
347 Since:
348 */
dom_node_previous_sibling_read(dom_object * obj,zval * retval)349 int dom_node_previous_sibling_read(dom_object *obj, zval *retval)
350 {
351 xmlNode *nodep, *prevsib;
352
353 nodep = dom_object_get_node(obj);
354
355 if (nodep == NULL) {
356 php_dom_throw_error(INVALID_STATE_ERR, 0);
357 return FAILURE;
358 }
359
360 prevsib = nodep->prev;
361 if (!prevsib) {
362 ZVAL_NULL(retval);
363 return SUCCESS;
364 }
365
366 php_dom_create_object(prevsib, retval, obj);
367 return SUCCESS;
368 }
369
370 /* }}} */
371
372 /* {{{ nextSibling DomNode
373 readonly=yes
374 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6AC54C2F
375 Since:
376 */
dom_node_next_sibling_read(dom_object * obj,zval * retval)377 int dom_node_next_sibling_read(dom_object *obj, zval *retval)
378 {
379 xmlNode *nodep, *nextsib;
380
381 nodep = dom_object_get_node(obj);
382
383 if (nodep == NULL) {
384 php_dom_throw_error(INVALID_STATE_ERR, 0);
385 return FAILURE;
386 }
387
388 nextsib = nodep->next;
389 if (!nextsib) {
390 ZVAL_NULL(retval);
391 return SUCCESS;
392 }
393
394 php_dom_create_object(nextsib, retval, obj);
395 return SUCCESS;
396 }
397
398 /* }}} */
399
400 /* {{{ previousElementSibling DomNode
401 readonly=yes
402 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-640FB3C8
403 Since:
404 */
dom_node_previous_element_sibling_read(dom_object * obj,zval * retval)405 int dom_node_previous_element_sibling_read(dom_object *obj, zval *retval)
406 {
407 xmlNode *nodep, *prevsib;
408
409 nodep = dom_object_get_node(obj);
410
411 if (nodep == NULL) {
412 php_dom_throw_error(INVALID_STATE_ERR, 0);
413 return FAILURE;
414 }
415
416 prevsib = nodep->prev;
417
418 while (prevsib && prevsib->type != XML_ELEMENT_NODE) {
419 prevsib = prevsib->prev;
420 }
421
422 if (!prevsib) {
423 ZVAL_NULL(retval);
424 return SUCCESS;
425 }
426
427 php_dom_create_object(prevsib, retval, obj);
428 return SUCCESS;
429 }
430
431 /* }}} */
432
433 /* {{{ nextElementSibling DomNode
434 readonly=yes
435 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6AC54C2F
436 Since:
437 */
dom_node_next_element_sibling_read(dom_object * obj,zval * retval)438 int dom_node_next_element_sibling_read(dom_object *obj, zval *retval)
439 {
440 xmlNode *nodep, *nextsib;
441
442 nodep = dom_object_get_node(obj);
443
444 if (nodep == NULL) {
445 php_dom_throw_error(INVALID_STATE_ERR, 0);
446 return FAILURE;
447 }
448
449 nextsib = nodep->next;
450
451 while (nextsib != NULL && nextsib->type != XML_ELEMENT_NODE) {
452 nextsib = nextsib->next;
453 }
454
455 if (!nextsib) {
456 ZVAL_NULL(retval);
457 return SUCCESS;
458 }
459
460 php_dom_create_object(nextsib, retval, obj);
461 return SUCCESS;
462 }
463
464 /* }}} */
465
466 /* {{{ attributes DomNamedNodeMap
467 readonly=yes
468 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-84CF096
469 Since:
470 */
dom_node_attributes_read(dom_object * obj,zval * retval)471 int dom_node_attributes_read(dom_object *obj, zval *retval)
472 {
473 xmlNode *nodep = dom_object_get_node(obj);
474 dom_object *intern;
475
476 if (nodep == NULL) {
477 php_dom_throw_error(INVALID_STATE_ERR, 0);
478 return FAILURE;
479 }
480
481 if (nodep->type == XML_ELEMENT_NODE) {
482 php_dom_create_iterator(retval, DOM_NAMEDNODEMAP);
483 intern = Z_DOMOBJ_P(retval);
484 dom_namednode_iter(obj, XML_ATTRIBUTE_NODE, intern, NULL, NULL, NULL);
485 } else {
486 ZVAL_NULL(retval);
487 }
488
489 return SUCCESS;
490 }
491
492 /* }}} */
493
494 /* {{{ ownerDocument DomDocument
495 readonly=yes
496 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-node-ownerDoc
497 Since:
498 */
dom_node_owner_document_read(dom_object * obj,zval * retval)499 int dom_node_owner_document_read(dom_object *obj, zval *retval)
500 {
501 xmlNode *nodep = dom_object_get_node(obj);
502 xmlDocPtr docp;
503
504 if (nodep == NULL) {
505 php_dom_throw_error(INVALID_STATE_ERR, 0);
506 return FAILURE;
507 }
508
509 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
510 ZVAL_NULL(retval);
511 return SUCCESS;
512 }
513
514 docp = nodep->doc;
515 if (!docp) {
516 return FAILURE;
517 }
518
519 php_dom_create_object((xmlNodePtr) docp, retval, obj);
520 return SUCCESS;
521 }
522
523 /* }}} */
524
525 /* {{{ namespaceUri string
526 readonly=yes
527 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSname
528 Since: DOM Level 2
529 */
dom_node_namespace_uri_read(dom_object * obj,zval * retval)530 int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
531 {
532 xmlNode *nodep = dom_object_get_node(obj);
533 char *str = NULL;
534
535 if (nodep == NULL) {
536 php_dom_throw_error(INVALID_STATE_ERR, 0);
537 return FAILURE;
538 }
539
540 switch (nodep->type) {
541 case XML_ELEMENT_NODE:
542 case XML_ATTRIBUTE_NODE:
543 case XML_NAMESPACE_DECL:
544 if (nodep->ns != NULL) {
545 str = (char *) nodep->ns->href;
546 }
547 break;
548 default:
549 str = NULL;
550 break;
551 }
552
553 if (str != NULL) {
554 ZVAL_STRING(retval, str);
555 } else {
556 ZVAL_NULL(retval);
557 }
558
559 return SUCCESS;
560 }
561
562 /* }}} */
563
564 /* {{{ prefix string
565 readonly=no
566 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSPrefix
567 Since: DOM Level 2
568 */
dom_node_prefix_read(dom_object * obj,zval * retval)569 int dom_node_prefix_read(dom_object *obj, zval *retval)
570 {
571 xmlNode *nodep = dom_object_get_node(obj);
572 xmlNsPtr ns;
573 char *str = NULL;
574
575 if (nodep == NULL) {
576 php_dom_throw_error(INVALID_STATE_ERR, 0);
577 return FAILURE;
578 }
579
580 switch (nodep->type) {
581 case XML_ELEMENT_NODE:
582 case XML_ATTRIBUTE_NODE:
583 case XML_NAMESPACE_DECL:
584 ns = nodep->ns;
585 if (ns != NULL && ns->prefix) {
586 str = (char *) ns->prefix;
587 }
588 break;
589 default:
590 str = NULL;
591 break;
592 }
593
594 if (str == NULL) {
595 ZVAL_EMPTY_STRING(retval);
596 } else {
597 ZVAL_STRING(retval, str);
598 }
599 return SUCCESS;
600
601 }
602
dom_node_prefix_write(dom_object * obj,zval * newval)603 int dom_node_prefix_write(dom_object *obj, zval *newval)
604 {
605 zend_string *str;
606 xmlNode *nodep, *nsnode = NULL;
607 xmlNsPtr ns = NULL, curns;
608 char *strURI;
609 char *prefix;
610
611 nodep = dom_object_get_node(obj);
612
613 if (nodep == NULL) {
614 php_dom_throw_error(INVALID_STATE_ERR, 0);
615 return FAILURE;
616 }
617
618 switch (nodep->type) {
619 case XML_ELEMENT_NODE:
620 nsnode = nodep;
621 case XML_ATTRIBUTE_NODE:
622 if (nsnode == NULL) {
623 nsnode = nodep->parent;
624 if (nsnode == NULL) {
625 nsnode = xmlDocGetRootElement(nodep->doc);
626 }
627 }
628 str = zval_try_get_string(newval);
629 if (UNEXPECTED(!str)) {
630 return FAILURE;
631 }
632
633 prefix = ZSTR_VAL(str);
634 if (nsnode && nodep->ns != NULL && !xmlStrEqual(nodep->ns->prefix, (xmlChar *)prefix)) {
635 strURI = (char *) nodep->ns->href;
636 if (strURI == NULL ||
637 (!strcmp(prefix, "xml") && strcmp(strURI, (char *) XML_XML_NAMESPACE)) ||
638 (nodep->type == XML_ATTRIBUTE_NODE && !strcmp(prefix, "xmlns") &&
639 strcmp(strURI, (char *) DOM_XMLNS_NAMESPACE)) ||
640 (nodep->type == XML_ATTRIBUTE_NODE && !strcmp((char *) nodep->name, "xmlns"))) {
641 ns = NULL;
642 } else {
643 curns = nsnode->nsDef;
644 while (curns != NULL) {
645 if (xmlStrEqual((xmlChar *)prefix, curns->prefix) && xmlStrEqual(nodep->ns->href, curns->href)) {
646 ns = curns;
647 break;
648 }
649 curns = curns->next;
650 }
651 if (ns == NULL) {
652 ns = xmlNewNs(nsnode, nodep->ns->href, (xmlChar *)prefix);
653 }
654 }
655
656 if (ns == NULL) {
657 zend_string_release_ex(str, 0);
658 php_dom_throw_error(NAMESPACE_ERR, dom_get_strict_error(obj->document));
659 return FAILURE;
660 }
661
662 xmlSetNs(nodep, ns);
663 }
664 zend_string_release_ex(str, 0);
665 break;
666 default:
667 break;
668 }
669
670 return SUCCESS;
671 }
672
673 /* }}} */
674
675 /* {{{ localName string
676 readonly=yes
677 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeNSLocalN
678 Since: DOM Level 2
679 */
dom_node_local_name_read(dom_object * obj,zval * retval)680 int dom_node_local_name_read(dom_object *obj, zval *retval)
681 {
682 xmlNode *nodep = dom_object_get_node(obj);
683
684 if (nodep == NULL) {
685 php_dom_throw_error(INVALID_STATE_ERR, 0);
686 return FAILURE;
687 }
688
689 if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE || nodep->type == XML_NAMESPACE_DECL) {
690 ZVAL_STRING(retval, (char *) (nodep->name));
691 } else {
692 ZVAL_NULL(retval);
693 }
694
695 return SUCCESS;
696 }
697
698 /* }}} */
699
700 /* {{{ baseURI string
701 readonly=yes
702 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-baseURI
703 Since: DOM Level 3
704 */
dom_node_base_uri_read(dom_object * obj,zval * retval)705 int dom_node_base_uri_read(dom_object *obj, zval *retval)
706 {
707 xmlNode *nodep = dom_object_get_node(obj);
708 xmlChar *baseuri;
709
710 if (nodep == NULL) {
711 php_dom_throw_error(INVALID_STATE_ERR, 0);
712 return FAILURE;
713 }
714
715 baseuri = xmlNodeGetBase(nodep->doc, nodep);
716 if (baseuri) {
717 ZVAL_STRING(retval, (char *) (baseuri));
718 xmlFree(baseuri);
719 } else {
720 ZVAL_NULL(retval);
721 }
722
723 return SUCCESS;
724 }
725
726 /* }}} */
727
728 /* {{{ textContent string
729 readonly=no
730 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-textContent
731 Since: DOM Level 3
732 */
dom_node_text_content_read(dom_object * obj,zval * retval)733 int dom_node_text_content_read(dom_object *obj, zval *retval)
734 {
735 xmlNode *nodep = dom_object_get_node(obj);
736 char *str = NULL;
737
738 if (nodep == NULL) {
739 php_dom_throw_error(INVALID_STATE_ERR, 0);
740 return FAILURE;
741 }
742
743 str = (char *) xmlNodeGetContent(nodep);
744
745 if (str != NULL) {
746 ZVAL_STRING(retval, str);
747 xmlFree(str);
748 } else {
749 ZVAL_EMPTY_STRING(retval);
750 }
751
752 return SUCCESS;
753 }
754
dom_node_text_content_write(dom_object * obj,zval * newval)755 int dom_node_text_content_write(dom_object *obj, zval *newval)
756 {
757 xmlNode *nodep = dom_object_get_node(obj);
758 zend_string *str;
759
760 if (nodep == NULL) {
761 php_dom_throw_error(INVALID_STATE_ERR, 0);
762 return FAILURE;
763 }
764
765 str = zval_try_get_string(newval);
766 if (UNEXPECTED(!str)) {
767 return FAILURE;
768 }
769
770 if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE) {
771 if (nodep->children) {
772 node_list_unlink(nodep->children);
773 php_libxml_node_free_list((xmlNodePtr) nodep->children);
774 nodep->children = NULL;
775 }
776 }
777
778 /* we have to use xmlNodeAddContent() to get the same behavior as with xmlNewText() */
779 xmlNodeSetContent(nodep, (xmlChar *) "");
780 xmlNodeAddContent(nodep, (xmlChar *) ZSTR_VAL(str));
781 zend_string_release_ex(str, 0);
782
783 return SUCCESS;
784 }
785
786 /* }}} */
787
_php_dom_insert_fragment(xmlNodePtr nodep,xmlNodePtr prevsib,xmlNodePtr nextsib,xmlNodePtr fragment,dom_object * intern,dom_object * childobj)788 static xmlNodePtr _php_dom_insert_fragment(xmlNodePtr nodep, xmlNodePtr prevsib, xmlNodePtr nextsib, xmlNodePtr fragment, dom_object *intern, dom_object *childobj) /* {{{ */
789 {
790 xmlNodePtr newchild, node;
791
792 newchild = fragment->children;
793
794 if (newchild) {
795 if (prevsib == NULL) {
796 nodep->children = newchild;
797 } else {
798 prevsib->next = newchild;
799 }
800 newchild->prev = prevsib;
801 if (nextsib == NULL) {
802 nodep->last = fragment->last;
803 } else {
804 fragment->last->next = nextsib;
805 nextsib->prev = fragment->last;
806 }
807
808 node = newchild;
809 while (node != NULL) {
810 node->parent = nodep;
811 if (node->doc != nodep->doc) {
812 xmlSetTreeDoc(node, nodep->doc);
813 if (node->_private != NULL) {
814 childobj = node->_private;
815 childobj->document = intern->document;
816 php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
817 }
818 }
819 if (node == fragment->last) {
820 break;
821 }
822 node = node->next;
823 }
824
825 fragment->children = NULL;
826 fragment->last = NULL;
827 }
828
829 return newchild;
830 }
831 /* }}} */
832
833 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-952280727
834 Since:
835 */
PHP_METHOD(DOMNode,insertBefore)836 PHP_METHOD(DOMNode, insertBefore)
837 {
838 zval *id, *node, *ref = NULL;
839 xmlNodePtr child, new_child, parentp, refp;
840 dom_object *intern, *childobj, *refpobj;
841 int ret, stricterror;
842
843 id = ZEND_THIS;
844 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|O!", &node, dom_node_class_entry, &ref, dom_node_class_entry) == FAILURE) {
845 RETURN_THROWS();
846 }
847
848 DOM_GET_OBJ(parentp, id, xmlNodePtr, intern);
849
850 if (dom_node_children_valid(parentp) == FAILURE) {
851 RETURN_FALSE;
852 }
853
854 DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
855
856 new_child = NULL;
857
858 stricterror = dom_get_strict_error(intern->document);
859
860 if (dom_node_is_read_only(parentp) == SUCCESS ||
861 (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
862 php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
863 RETURN_FALSE;
864 }
865
866 if (dom_hierarchy(parentp, child) == FAILURE) {
867 php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
868 RETURN_FALSE;
869 }
870
871 if (child->doc != parentp->doc && child->doc != NULL) {
872 php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
873 RETURN_FALSE;
874 }
875
876 if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) {
877 /* TODO Drop Warning? */
878 php_error_docref(NULL, E_WARNING, "Document Fragment is empty");
879 RETURN_FALSE;
880 }
881
882 if (child->doc == NULL && parentp->doc != NULL) {
883 childobj->document = intern->document;
884 php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
885 }
886
887 if (ref != NULL) {
888 DOM_GET_OBJ(refp, ref, xmlNodePtr, refpobj);
889 if (refp->parent != parentp) {
890 php_dom_throw_error(NOT_FOUND_ERR, stricterror);
891 RETURN_FALSE;
892 }
893
894 if (child->parent != NULL) {
895 xmlUnlinkNode(child);
896 }
897
898 if (child->type == XML_TEXT_NODE && (refp->type == XML_TEXT_NODE ||
899 (refp->prev != NULL && refp->prev->type == XML_TEXT_NODE))) {
900 if (child->doc == NULL) {
901 xmlSetTreeDoc(child, parentp->doc);
902 }
903 new_child = child;
904 new_child->parent = refp->parent;
905 new_child->next = refp;
906 new_child->prev = refp->prev;
907 refp->prev = new_child;
908 if (new_child->prev != NULL) {
909 new_child->prev->next = new_child;
910 }
911 if (new_child->parent != NULL) {
912 if (new_child->parent->children == refp) {
913 new_child->parent->children = new_child;
914 }
915 }
916
917 } else if (child->type == XML_ATTRIBUTE_NODE) {
918 xmlAttrPtr lastattr;
919
920 if (child->ns == NULL)
921 lastattr = xmlHasProp(refp->parent, child->name);
922 else
923 lastattr = xmlHasNsProp(refp->parent, child->name, child->ns->href);
924 if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
925 if (lastattr != (xmlAttrPtr) child) {
926 xmlUnlinkNode((xmlNodePtr) lastattr);
927 php_libxml_node_free_resource((xmlNodePtr) lastattr);
928 } else {
929 DOM_RET_OBJ(child, &ret, intern);
930 return;
931 }
932 }
933 } else if (child->type == XML_DOCUMENT_FRAG_NODE) {
934 new_child = _php_dom_insert_fragment(parentp, refp->prev, refp, child, intern, childobj);
935 }
936
937 if (new_child == NULL) {
938 new_child = xmlAddPrevSibling(refp, child);
939 }
940 } else {
941 if (child->parent != NULL){
942 xmlUnlinkNode(child);
943 }
944 if (child->type == XML_TEXT_NODE && parentp->last != NULL && parentp->last->type == XML_TEXT_NODE) {
945 child->parent = parentp;
946 if (child->doc == NULL) {
947 xmlSetTreeDoc(child, parentp->doc);
948 }
949 new_child = child;
950 if (parentp->children == NULL) {
951 parentp->children = child;
952 parentp->last = child;
953 } else {
954 child = parentp->last;
955 child->next = new_child;
956 new_child->prev = child;
957 parentp->last = new_child;
958 }
959 } else if (child->type == XML_ATTRIBUTE_NODE) {
960 xmlAttrPtr lastattr;
961
962 if (child->ns == NULL)
963 lastattr = xmlHasProp(parentp, child->name);
964 else
965 lastattr = xmlHasNsProp(parentp, child->name, child->ns->href);
966 if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
967 if (lastattr != (xmlAttrPtr) child) {
968 xmlUnlinkNode((xmlNodePtr) lastattr);
969 php_libxml_node_free_resource((xmlNodePtr) lastattr);
970 } else {
971 DOM_RET_OBJ(child, &ret, intern);
972 return;
973 }
974 }
975 } else if (child->type == XML_DOCUMENT_FRAG_NODE) {
976 new_child = _php_dom_insert_fragment(parentp, parentp->last, NULL, child, intern, childobj);
977 }
978 if (new_child == NULL) {
979 new_child = xmlAddChild(parentp, child);
980 }
981 }
982
983 if (NULL == new_child) {
984 zend_throw_error(NULL, "Cannot add newnode as the previous sibling of refnode");
985 RETURN_THROWS();
986 }
987
988 dom_reconcile_ns(parentp->doc, new_child);
989
990 DOM_RET_OBJ(new_child, &ret, intern);
991
992 }
993 /* }}} end dom_node_insert_before */
994
995 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-785887307
996 Since:
997 */
PHP_METHOD(DOMNode,replaceChild)998 PHP_METHOD(DOMNode, replaceChild)
999 {
1000 zval *id, *newnode, *oldnode;
1001 xmlNodePtr children, newchild, oldchild, nodep;
1002 dom_object *intern, *newchildobj, *oldchildobj;
1003 int foundoldchild = 0, stricterror;
1004
1005 int ret;
1006
1007 id = ZEND_THIS;
1008 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &newnode, dom_node_class_entry, &oldnode, dom_node_class_entry) == FAILURE) {
1009 RETURN_THROWS();
1010 }
1011
1012 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1013
1014 if (dom_node_children_valid(nodep) == FAILURE) {
1015 RETURN_FALSE;
1016 }
1017
1018 DOM_GET_OBJ(newchild, newnode, xmlNodePtr, newchildobj);
1019 DOM_GET_OBJ(oldchild, oldnode, xmlNodePtr, oldchildobj);
1020
1021 children = nodep->children;
1022 if (!children) {
1023 RETURN_FALSE;
1024 }
1025
1026 stricterror = dom_get_strict_error(intern->document);
1027
1028 if (dom_node_is_read_only(nodep) == SUCCESS ||
1029 (newchild->parent != NULL && dom_node_is_read_only(newchild->parent) == SUCCESS)) {
1030 php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1031 RETURN_FALSE;
1032 }
1033
1034 if (newchild->doc != nodep->doc && newchild->doc != NULL) {
1035 php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
1036 RETURN_FALSE;
1037 }
1038
1039 if (dom_hierarchy(nodep, newchild) == FAILURE) {
1040 php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
1041 RETURN_FALSE;
1042 }
1043
1044 /* check for the old child and whether the new child is already a child */
1045 while (children) {
1046 if (children == oldchild) {
1047 foundoldchild = 1;
1048 break;
1049 }
1050 children = children->next;
1051 }
1052
1053 if (foundoldchild) {
1054 if (newchild->type == XML_DOCUMENT_FRAG_NODE) {
1055 xmlNodePtr prevsib, nextsib;
1056 prevsib = oldchild->prev;
1057 nextsib = oldchild->next;
1058
1059 xmlUnlinkNode(oldchild);
1060
1061 newchild = _php_dom_insert_fragment(nodep, prevsib, nextsib, newchild, intern, newchildobj);
1062 if (newchild) {
1063 dom_reconcile_ns(nodep->doc, newchild);
1064 }
1065 } else if (oldchild != newchild) {
1066 if (newchild->doc == NULL && nodep->doc != NULL) {
1067 xmlSetTreeDoc(newchild, nodep->doc);
1068 newchildobj->document = intern->document;
1069 php_libxml_increment_doc_ref((php_libxml_node_object *)newchildobj, NULL);
1070 }
1071 xmlReplaceNode(oldchild, newchild);
1072 dom_reconcile_ns(nodep->doc, newchild);
1073 }
1074 DOM_RET_OBJ(oldchild, &ret, intern);
1075 return;
1076 } else {
1077 php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1078 RETURN_FALSE;
1079 }
1080 }
1081 /* }}} end dom_node_replace_child */
1082
1083 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1734834066
1084 Since:
1085 */
PHP_METHOD(DOMNode,removeChild)1086 PHP_METHOD(DOMNode, removeChild)
1087 {
1088 zval *id, *node;
1089 xmlNodePtr children, child, nodep;
1090 dom_object *intern, *childobj;
1091 int ret, stricterror;
1092
1093 id = ZEND_THIS;
1094 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1095 RETURN_THROWS();
1096 }
1097
1098 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1099
1100 if (dom_node_children_valid(nodep) == FAILURE) {
1101 RETURN_FALSE;
1102 }
1103
1104 DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
1105
1106 stricterror = dom_get_strict_error(intern->document);
1107
1108 if (dom_node_is_read_only(nodep) == SUCCESS ||
1109 (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
1110 php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1111 RETURN_FALSE;
1112 }
1113
1114 children = nodep->children;
1115 if (!children) {
1116 php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1117 RETURN_FALSE;
1118 }
1119
1120 while (children) {
1121 if (children == child) {
1122 xmlUnlinkNode(child);
1123 DOM_RET_OBJ(child, &ret, intern);
1124 return;
1125 }
1126 children = children->next;
1127 }
1128
1129 php_dom_throw_error(NOT_FOUND_ERR, stricterror);
1130 RETURN_FALSE;
1131 }
1132 /* }}} end dom_node_remove_child */
1133
1134 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-184E7107
1135 Since:
1136 */
PHP_METHOD(DOMNode,appendChild)1137 PHP_METHOD(DOMNode, appendChild)
1138 {
1139 zval *id, *node;
1140 xmlNodePtr child, nodep, new_child = NULL;
1141 dom_object *intern, *childobj;
1142 int ret, stricterror;
1143
1144 id = ZEND_THIS;
1145 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1146 RETURN_THROWS();
1147 }
1148
1149 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1150
1151 if (dom_node_children_valid(nodep) == FAILURE) {
1152 RETURN_FALSE;
1153 }
1154
1155 DOM_GET_OBJ(child, node, xmlNodePtr, childobj);
1156
1157 stricterror = dom_get_strict_error(intern->document);
1158
1159 if (dom_node_is_read_only(nodep) == SUCCESS ||
1160 (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
1161 php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
1162 RETURN_FALSE;
1163 }
1164
1165 if (dom_hierarchy(nodep, child) == FAILURE) {
1166 php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
1167 RETURN_FALSE;
1168 }
1169
1170 if (!(child->doc == NULL || child->doc == nodep->doc)) {
1171 php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
1172 RETURN_FALSE;
1173 }
1174
1175 if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) {
1176 /* TODO Drop Warning? */
1177 php_error_docref(NULL, E_WARNING, "Document Fragment is empty");
1178 RETURN_FALSE;
1179 }
1180
1181 if (child->doc == NULL && nodep->doc != NULL) {
1182 childobj->document = intern->document;
1183 php_libxml_increment_doc_ref((php_libxml_node_object *)childobj, NULL);
1184 }
1185
1186 if (child->parent != NULL){
1187 xmlUnlinkNode(child);
1188 }
1189
1190 if (child->type == XML_TEXT_NODE && nodep->last != NULL && nodep->last->type == XML_TEXT_NODE) {
1191 child->parent = nodep;
1192 if (child->doc == NULL) {
1193 xmlSetTreeDoc(child, nodep->doc);
1194 }
1195 new_child = child;
1196 if (nodep->children == NULL) {
1197 nodep->children = child;
1198 nodep->last = child;
1199 } else {
1200 child = nodep->last;
1201 child->next = new_child;
1202 new_child->prev = child;
1203 nodep->last = new_child;
1204 }
1205 } else if (child->type == XML_ATTRIBUTE_NODE) {
1206 xmlAttrPtr lastattr;
1207
1208 if (child->ns == NULL)
1209 lastattr = xmlHasProp(nodep, child->name);
1210 else
1211 lastattr = xmlHasNsProp(nodep, child->name, child->ns->href);
1212 if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) {
1213 if (lastattr != (xmlAttrPtr) child) {
1214 xmlUnlinkNode((xmlNodePtr) lastattr);
1215 php_libxml_node_free_resource((xmlNodePtr) lastattr);
1216 }
1217 }
1218 } else if (child->type == XML_DOCUMENT_FRAG_NODE) {
1219 new_child = _php_dom_insert_fragment(nodep, nodep->last, NULL, child, intern, childobj);
1220 }
1221
1222 if (new_child == NULL) {
1223 new_child = xmlAddChild(nodep, child);
1224 if (new_child == NULL) {
1225 // TODO Convert to Error?
1226 php_error_docref(NULL, E_WARNING, "Couldn't append node");
1227 RETURN_FALSE;
1228 }
1229 }
1230
1231 dom_reconcile_ns(nodep->doc, new_child);
1232
1233 DOM_RET_OBJ(new_child, &ret, intern);
1234 }
1235 /* }}} end dom_node_append_child */
1236
1237 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-810594187
1238 Since:
1239 */
PHP_METHOD(DOMNode,hasChildNodes)1240 PHP_METHOD(DOMNode, hasChildNodes)
1241 {
1242 zval *id;
1243 xmlNode *nodep;
1244 dom_object *intern;
1245
1246 id = ZEND_THIS;
1247 if (zend_parse_parameters_none() == FAILURE) {
1248 RETURN_THROWS();
1249 }
1250
1251 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1252
1253 if (dom_node_children_valid(nodep) == FAILURE) {
1254 RETURN_FALSE;
1255 }
1256
1257 if (nodep->children) {
1258 RETURN_TRUE;
1259 } else {
1260 RETURN_FALSE;
1261 }
1262 }
1263 /* }}} end dom_node_has_child_nodes */
1264
1265 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3A0ED0A4
1266 Since:
1267 */
PHP_METHOD(DOMNode,cloneNode)1268 PHP_METHOD(DOMNode, cloneNode)
1269 {
1270 zval *id;
1271 xmlNode *n, *node;
1272 int ret;
1273 dom_object *intern;
1274 zend_bool recursive = 0;
1275
1276 id = ZEND_THIS;
1277 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &recursive) == FAILURE) {
1278 RETURN_THROWS();
1279 }
1280
1281 DOM_GET_OBJ(n, id, xmlNodePtr, intern);
1282
1283 node = xmlDocCopyNode(n, n->doc, recursive);
1284
1285 if (!node) {
1286 RETURN_FALSE;
1287 }
1288
1289 /* When deep is false Element nodes still require the attributes
1290 Following taken from libxml as xmlDocCopyNode doesn't do this */
1291 if (n->type == XML_ELEMENT_NODE && recursive == 0) {
1292 if (n->nsDef != NULL) {
1293 node->nsDef = xmlCopyNamespaceList(n->nsDef);
1294 }
1295 if (n->ns != NULL) {
1296 xmlNsPtr ns;
1297 ns = xmlSearchNs(n->doc, node, n->ns->prefix);
1298 if (ns == NULL) {
1299 ns = xmlSearchNs(n->doc, n, n->ns->prefix);
1300 if (ns != NULL) {
1301 xmlNodePtr root = node;
1302
1303 while (root->parent != NULL) {
1304 root = root->parent;
1305 }
1306 node->ns = xmlNewNs(root, ns->href, ns->prefix);
1307 }
1308 } else {
1309 node->ns = ns;
1310 }
1311 }
1312 if (n->properties != NULL) {
1313 node->properties = xmlCopyPropList(node, n->properties);
1314 }
1315 }
1316
1317 /* If document cloned we want a new document proxy */
1318 if (node->doc != n->doc) {
1319 intern = NULL;
1320 }
1321
1322 DOM_RET_OBJ(node, &ret, intern);
1323 }
1324 /* }}} end dom_node_clone_node */
1325
1326 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-normalize
1327 Since:
1328 */
PHP_METHOD(DOMNode,normalize)1329 PHP_METHOD(DOMNode, normalize)
1330 {
1331 zval *id;
1332 xmlNode *nodep;
1333 dom_object *intern;
1334
1335 id = ZEND_THIS;
1336 if (zend_parse_parameters_none() == FAILURE) {
1337 RETURN_THROWS();
1338 }
1339
1340 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1341
1342 dom_normalize(nodep);
1343
1344 }
1345 /* }}} end dom_node_normalize */
1346
1347 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Level-2-Core-Node-supports
1348 Since: DOM Level 2
1349 */
PHP_METHOD(DOMNode,isSupported)1350 PHP_METHOD(DOMNode, isSupported)
1351 {
1352 size_t feature_len, version_len;
1353 char *feature, *version;
1354
1355 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &feature, &feature_len, &version, &version_len) == FAILURE) {
1356 RETURN_THROWS();
1357 }
1358
1359 if (dom_has_feature(feature, version)) {
1360 RETURN_TRUE;
1361 } else {
1362 RETURN_FALSE;
1363 }
1364 }
1365 /* }}} end dom_node_is_supported */
1366
1367 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-NodeHasAttrs
1368 Since: DOM Level 2
1369 */
PHP_METHOD(DOMNode,hasAttributes)1370 PHP_METHOD(DOMNode, hasAttributes)
1371 {
1372 zval *id;
1373 xmlNode *nodep;
1374 dom_object *intern;
1375
1376 id = ZEND_THIS;
1377 if (zend_parse_parameters_none() == FAILURE) {
1378 RETURN_THROWS();
1379 }
1380
1381 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1382
1383 if (nodep->type != XML_ELEMENT_NODE)
1384 RETURN_FALSE;
1385
1386 if (nodep->properties) {
1387 RETURN_TRUE;
1388 } else {
1389 RETURN_FALSE;
1390 }
1391 }
1392 /* }}} end dom_node_has_attributes */
1393
1394 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-isSameNode
1395 Since: DOM Level 3
1396 */
PHP_METHOD(DOMNode,isSameNode)1397 PHP_METHOD(DOMNode, isSameNode)
1398 {
1399 zval *id, *node;
1400 xmlNodePtr nodeotherp, nodep;
1401 dom_object *intern, *nodeotherobj;
1402
1403 id = ZEND_THIS;
1404 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_node_class_entry) == FAILURE) {
1405 RETURN_THROWS();
1406 }
1407
1408 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1409
1410 DOM_GET_OBJ(nodeotherp, node, xmlNodePtr, nodeotherobj);
1411
1412 if (nodep == nodeotherp) {
1413 RETURN_TRUE;
1414 } else {
1415 RETURN_FALSE;
1416 }
1417 }
1418 /* }}} end dom_node_is_same_node */
1419
1420 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-lookupNamespacePrefix
1421 Since: DOM Level 3
1422 */
PHP_METHOD(DOMNode,lookupPrefix)1423 PHP_METHOD(DOMNode, lookupPrefix)
1424 {
1425 zval *id;
1426 xmlNodePtr nodep, lookupp = NULL;
1427 dom_object *intern;
1428 xmlNsPtr nsptr;
1429 size_t uri_len = 0;
1430 char *uri;
1431
1432 id = ZEND_THIS;
1433 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &uri, &uri_len) == FAILURE) {
1434 RETURN_THROWS();
1435 }
1436
1437 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1438
1439 if (uri_len > 0) {
1440 switch (nodep->type) {
1441 case XML_ELEMENT_NODE:
1442 lookupp = nodep;
1443 break;
1444 case XML_DOCUMENT_NODE:
1445 case XML_HTML_DOCUMENT_NODE:
1446 lookupp = xmlDocGetRootElement((xmlDocPtr) nodep);
1447 break;
1448 case XML_ENTITY_NODE :
1449 case XML_NOTATION_NODE:
1450 case XML_DOCUMENT_FRAG_NODE:
1451 case XML_DOCUMENT_TYPE_NODE:
1452 case XML_DTD_NODE:
1453 RETURN_NULL();
1454 break;
1455 default:
1456 lookupp = nodep->parent;
1457 }
1458
1459 if (lookupp != NULL) {
1460 nsptr = xmlSearchNsByHref(lookupp->doc, lookupp, (xmlChar *) uri);
1461 if (nsptr && nsptr->prefix != NULL) {
1462 RETURN_STRING((char *) nsptr->prefix);
1463 }
1464 }
1465 }
1466
1467 RETURN_NULL();
1468 }
1469 /* }}} end dom_node_lookup_prefix */
1470
1471 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-isDefaultNamespace
1472 Since: DOM Level 3
1473 */
PHP_METHOD(DOMNode,isDefaultNamespace)1474 PHP_METHOD(DOMNode, isDefaultNamespace)
1475 {
1476 zval *id;
1477 xmlNodePtr nodep;
1478 dom_object *intern;
1479 xmlNsPtr nsptr;
1480 size_t uri_len = 0;
1481 char *uri;
1482
1483 id = ZEND_THIS;
1484 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &uri, &uri_len) == FAILURE) {
1485 RETURN_THROWS();
1486 }
1487
1488 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1489 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
1490 nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
1491 }
1492
1493 if (nodep && uri_len > 0) {
1494 nsptr = xmlSearchNs(nodep->doc, nodep, NULL);
1495 if (nsptr && xmlStrEqual(nsptr->href, (xmlChar *) uri)) {
1496 RETURN_TRUE;
1497 }
1498 }
1499
1500 RETURN_FALSE;
1501 }
1502 /* }}} end dom_node_is_default_namespace */
1503
1504 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI
1505 Since: DOM Level 3
1506 */
PHP_METHOD(DOMNode,lookupNamespaceURI)1507 PHP_METHOD(DOMNode, lookupNamespaceURI)
1508 {
1509 zval *id;
1510 xmlNodePtr nodep;
1511 dom_object *intern;
1512 xmlNsPtr nsptr;
1513 size_t prefix_len;
1514 char *prefix;
1515
1516 id = ZEND_THIS;
1517 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &prefix, &prefix_len) == FAILURE) {
1518 RETURN_THROWS();
1519 }
1520
1521 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1522 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
1523 nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
1524 if (nodep == NULL) {
1525 RETURN_NULL();
1526 }
1527 }
1528
1529 nsptr = xmlSearchNs(nodep->doc, nodep, (xmlChar *) prefix);
1530 if (nsptr && nsptr->href != NULL) {
1531 RETURN_STRING((char *) nsptr->href);
1532 }
1533
1534 RETURN_NULL();
1535 }
1536 /* }}} end dom_node_lookup_namespace_uri */
1537
dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS,int mode)1538 static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1539 {
1540 zval *id;
1541 zval *xpath_array=NULL, *ns_prefixes=NULL;
1542 xmlNodePtr nodep;
1543 xmlDocPtr docp;
1544 xmlNodeSetPtr nodeset = NULL;
1545 dom_object *intern;
1546 zend_bool exclusive=0, with_comments=0;
1547 xmlChar **inclusive_ns_prefixes = NULL;
1548 char *file = NULL;
1549 int ret = -1;
1550 size_t file_len = 0;
1551 xmlOutputBufferPtr buf;
1552 xmlXPathContextPtr ctxp=NULL;
1553 xmlXPathObjectPtr xpathobjp=NULL;
1554
1555 id = ZEND_THIS;
1556 if (mode == 0) {
1557 if (zend_parse_parameters(ZEND_NUM_ARGS(),
1558 "|bba!a!", &exclusive, &with_comments,
1559 &xpath_array, &ns_prefixes) == FAILURE) {
1560 RETURN_THROWS();
1561 }
1562 } else {
1563 if (zend_parse_parameters(ZEND_NUM_ARGS(),
1564 "s|bba!a!", &file, &file_len, &exclusive,
1565 &with_comments, &xpath_array, &ns_prefixes) == FAILURE) {
1566 RETURN_THROWS();
1567 }
1568 }
1569
1570 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1571
1572 docp = nodep->doc;
1573
1574 if (! docp) {
1575 zend_throw_error(NULL, "Node must be associated with a document");
1576 RETURN_THROWS();
1577 }
1578
1579 if (xpath_array == NULL) {
1580 if (nodep->type != XML_DOCUMENT_NODE) {
1581 ctxp = xmlXPathNewContext(docp);
1582 ctxp->node = nodep;
1583 xpathobjp = xmlXPathEvalExpression((xmlChar *) "(.//. | .//@* | .//namespace::*)", ctxp);
1584 ctxp->node = NULL;
1585 if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
1586 nodeset = xpathobjp->nodesetval;
1587 } else {
1588 if (xpathobjp) {
1589 xmlXPathFreeObject(xpathobjp);
1590 }
1591 xmlXPathFreeContext(ctxp);
1592 zend_throw_error(NULL, "XPath query did not return a nodeset");
1593 RETURN_THROWS();
1594 }
1595 }
1596 } else {
1597 /*xpath query from xpath_array */
1598 HashTable *ht = Z_ARRVAL_P(xpath_array);
1599 zval *tmp;
1600 char *xquery;
1601
1602 tmp = zend_hash_str_find(ht, "query", sizeof("query")-1);
1603 if (!tmp) {
1604 /* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */
1605 zend_argument_value_error(3 + mode, "must have a \"query\" key");
1606 RETURN_THROWS();
1607 }
1608 if (Z_TYPE_P(tmp) != IS_STRING) {
1609 /* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */
1610 zend_argument_type_error(3 + mode, "\"query\" option must be a string, %s given", zend_zval_type_name(tmp));
1611 RETURN_THROWS();
1612 }
1613 xquery = Z_STRVAL_P(tmp);
1614
1615 ctxp = xmlXPathNewContext(docp);
1616 ctxp->node = nodep;
1617
1618 tmp = zend_hash_str_find(ht, "namespaces", sizeof("namespaces")-1);
1619 if (tmp && Z_TYPE_P(tmp) == IS_ARRAY) {
1620 zval *tmpns;
1621 zend_string *prefix;
1622
1623 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(tmp), prefix, tmpns) {
1624 if (Z_TYPE_P(tmpns) == IS_STRING) {
1625 if (prefix) {
1626 xmlXPathRegisterNs(ctxp, (xmlChar *) ZSTR_VAL(prefix), (xmlChar *) Z_STRVAL_P(tmpns));
1627 }
1628 }
1629 } ZEND_HASH_FOREACH_END();
1630 }
1631
1632 xpathobjp = xmlXPathEvalExpression((xmlChar *) xquery, ctxp);
1633 ctxp->node = NULL;
1634 if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
1635 nodeset = xpathobjp->nodesetval;
1636 } else {
1637 if (xpathobjp) {
1638 xmlXPathFreeObject(xpathobjp);
1639 }
1640 xmlXPathFreeContext(ctxp);
1641 zend_throw_error(NULL, "XPath query did not return a nodeset");
1642 RETURN_THROWS();
1643 }
1644 }
1645
1646 if (ns_prefixes != NULL) {
1647 if (exclusive) {
1648 zval *tmpns;
1649 int nscount = 0;
1650
1651 inclusive_ns_prefixes = safe_emalloc(zend_hash_num_elements(Z_ARRVAL_P(ns_prefixes)) + 1,
1652 sizeof(xmlChar *), 0);
1653 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(ns_prefixes), tmpns) {
1654 if (Z_TYPE_P(tmpns) == IS_STRING) {
1655 inclusive_ns_prefixes[nscount++] = (xmlChar *) Z_STRVAL_P(tmpns);
1656 }
1657 } ZEND_HASH_FOREACH_END();
1658 inclusive_ns_prefixes[nscount] = NULL;
1659 } else {
1660 php_error_docref(NULL, E_NOTICE,
1661 "Inclusive namespace prefixes only allowed in exclusive mode.");
1662 }
1663 }
1664
1665 if (mode == 1) {
1666 buf = xmlOutputBufferCreateFilename(file, NULL, 0);
1667 } else {
1668 buf = xmlAllocOutputBuffer(NULL);
1669 }
1670
1671 if (buf != NULL) {
1672 ret = xmlC14NDocSaveTo(docp, nodeset, exclusive, inclusive_ns_prefixes,
1673 with_comments, buf);
1674 }
1675
1676 if (inclusive_ns_prefixes != NULL) {
1677 efree(inclusive_ns_prefixes);
1678 }
1679 if (xpathobjp != NULL) {
1680 xmlXPathFreeObject(xpathobjp);
1681 }
1682 if (ctxp != NULL) {
1683 xmlXPathFreeContext(ctxp);
1684 }
1685
1686 if (buf == NULL || ret < 0) {
1687 RETVAL_FALSE;
1688 } else {
1689 if (mode == 0) {
1690 #ifdef LIBXML2_NEW_BUFFER
1691 ret = xmlOutputBufferGetSize(buf);
1692 #else
1693 ret = buf->buffer->use;
1694 #endif
1695 if (ret > 0) {
1696 #ifdef LIBXML2_NEW_BUFFER
1697 RETVAL_STRINGL((char *) xmlOutputBufferGetContent(buf), ret);
1698 #else
1699 RETVAL_STRINGL((char *) buf->buffer->content, ret);
1700 #endif
1701 } else {
1702 RETVAL_EMPTY_STRING();
1703 }
1704 }
1705 }
1706
1707 if (buf) {
1708 int bytes;
1709
1710 bytes = xmlOutputBufferClose(buf);
1711 if (mode == 1 && (ret >= 0)) {
1712 RETURN_LONG(bytes);
1713 }
1714 }
1715 }
1716 /* }}} */
1717
1718 /* {{{ Canonicalize nodes to a string */
PHP_METHOD(DOMNode,C14N)1719 PHP_METHOD(DOMNode, C14N)
1720 {
1721 dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1722 }
1723 /* }}} */
1724
1725 /* {{{ Canonicalize nodes to a file */
PHP_METHOD(DOMNode,C14NFile)1726 PHP_METHOD(DOMNode, C14NFile)
1727 {
1728 dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1729 }
1730 /* }}} */
1731
1732 /* {{{ Gets an xpath for a node */
PHP_METHOD(DOMNode,getNodePath)1733 PHP_METHOD(DOMNode, getNodePath)
1734 {
1735 zval *id;
1736 xmlNode *nodep;
1737 dom_object *intern;
1738 char *value;
1739
1740 if (zend_parse_parameters_none() == FAILURE) {
1741 RETURN_THROWS();
1742 }
1743
1744 DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1745
1746 value = (char *) xmlGetNodePath(nodep);
1747 if (value == NULL) {
1748 /* TODO Research if can return empty string */
1749 RETURN_NULL();
1750 } else {
1751 RETVAL_STRING(value);
1752 xmlFree(value);
1753 }
1754 }
1755 /* }}} */
1756
1757 /* {{{ Gets line number for a node */
PHP_METHOD(DOMNode,getLineNo)1758 PHP_METHOD(DOMNode, getLineNo)
1759 {
1760 zval *id;
1761 xmlNode *nodep;
1762 dom_object *intern;
1763
1764 if (zend_parse_parameters_none() == FAILURE) {
1765 RETURN_THROWS();
1766 }
1767
1768 DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1769
1770 RETURN_LONG(xmlGetLineNo(nodep));
1771 }
1772 /* }}} */
1773
1774 #endif
1775