1/*
2  +----------------------------------------------------------------------+
3  | PHP Version 5                                                        |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 1997-2014 The PHP Group                                |
6  +----------------------------------------------------------------------+
7  | This source file is subject to version 3.01 of the PHP license,      |
8  | that is bundled with this package in the file LICENSE, and is        |
9  | available through the world-wide-web at the following url:           |
10  | http://www.php.net/license/3_01.txt                                  |
11  | If you did not receive a copy of the PHP license and are unable to   |
12  | obtain it through the world-wide-web, please send a note to          |
13  | license@php.net so we can mail you a copy immediately.               |
14  +----------------------------------------------------------------------+
15  | Authors: Sterling Hughes <sterling@php.net>                          |
16  |          Marcus Boerger <helly@php.net>                              |
17  |          Rob Richards <rrichards@php.net>                            |
18  +----------------------------------------------------------------------+
19*/
20
21/* $Id: db4944ff5ad867c6ddcfd17e31f3e94e85938fe6 $ */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "php.h"
28#if HAVE_LIBXML && HAVE_SIMPLEXML
29
30#include "php_ini.h"
31#include "ext/standard/info.h"
32#include "ext/standard/php_string.h"
33#include "php_simplexml.h"
34#include "php_simplexml_exports.h"
35#include "zend_exceptions.h"
36#include "zend_interfaces.h"
37#include "sxe.h"
38
39#define SXE_ELEMENT_BY_NAME 0
40
41zend_class_entry *sxe_class_entry = NULL;
42
43PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */
44{
45    return sxe_class_entry;
46}
47/* }}} */
48
49#define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags)
50#define SXE_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(simplexml_element, func, alias, arg_info, flags)
51
52#define SXE_METHOD(func) PHP_METHOD(simplexml_element, func)
53
54static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC);
55static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC);
56static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC);
57static zval *sxe_get_value(zval *z, zval *rv TSRMLS_DC);
58static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC);
59static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC);
60static zval *php_sxe_iterator_current_data(zend_object_iterator *iter TSRMLS_DC);
61static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC);
62static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC);
63static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC);
64
65/* {{{ _node_as_zval()
66 */
67static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix TSRMLS_DC)
68{
69    php_sxe_object *subnode;
70
71    subnode = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
72    subnode->document = sxe->document;
73    subnode->document->refcount++;
74    subnode->iter.type = itertype;
75    if (name) {
76        subnode->iter.name = xmlStrdup((xmlChar *)name);
77    }
78    if (nsprefix && *nsprefix) {
79        subnode->iter.nsprefix = xmlStrdup(nsprefix);
80        subnode->iter.isprefix = isprefix;
81    }
82
83    php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
84
85    ZVAL_OBJ(value, &subnode->zo);
86}
87/* }}} */
88
89#define APPEND_PREV_ELEMENT(__c, __v) \
90    if ((__c) == 1) { \
91        array_init(return_value); \
92        add_next_index_zval(return_value, __v); \
93    }
94
95#define APPEND_CUR_ELEMENT(__c, __v) \
96    if (++(__c) > 1) { \
97        add_next_index_zval(return_value, __v); \
98    }
99
100#define GET_NODE(__s, __n) { \
101    if ((__s)->node && (__s)->node->node) { \
102        __n = (__s)->node->node; \
103    } else { \
104        __n = NULL; \
105        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node no longer exists"); \
106    } \
107}
108
109static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node TSRMLS_DC) /* {{{ */
110{
111    php_sxe_object *intern;
112    xmlNodePtr retnode = NULL;
113
114    if (sxe && sxe->iter.type != SXE_ITER_NONE) {
115        php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
116        if (!Z_ISUNDEF(sxe->iter.data)) {
117            intern = Z_SXEOBJ_P(&sxe->iter.data);
118            GET_NODE(intern, retnode)
119        }
120        return retnode;
121    } else {
122        return node;
123    }
124}
125/* }}} */
126
127static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
128{
129    if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
130        return 1;
131    }
132
133    if (node->ns && !xmlStrcmp(prefix ? node->ns->prefix : node->ns->href, name)) {
134        return 1;
135    }
136
137    return 0;
138}
139/* }}} */
140
141static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, zend_long offset, xmlNodePtr node, zend_long *cnt) /* {{{ */
142{
143    zend_long nodendx = 0;
144
145    if (sxe->iter.type == SXE_ITER_NONE) {
146        if (offset == 0) {
147            if (cnt) {
148                *cnt = 0;
149            }
150            return node;
151        } else {
152            return NULL;
153        }
154    }
155    while (node && nodendx <= offset) {
156        SKIP_TEXT(node)
157        if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
158            if (sxe->iter.type == SXE_ITER_CHILD || (
159                sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) {
160                if (nodendx == offset) {
161                    break;
162                }
163                nodendx++;
164            }
165        }
166next_iter:
167        node = node->next;
168    }
169
170    if (cnt) {
171        *cnt = nodendx;
172    }
173
174    return node;
175}
176/* }}} */
177
178static xmlNodePtr sxe_find_element_by_name(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name TSRMLS_DC) /* {{{ */
179{
180    while (node) {
181        SKIP_TEXT(node)
182        if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
183            if (!xmlStrcmp(node->name, name)) {
184                return node;
185            }
186        }
187next_iter:
188        node = node->next;
189    }
190    return NULL;
191} /* }}} */
192
193static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, char **name, SXE_ITER *type TSRMLS_DC) /* {{{ */
194{
195    int         orgtype;
196    xmlNodePtr  orgnode = node;
197    xmlNodePtr  retnode = NULL;
198
199    if (sxe->iter.type != SXE_ITER_ATTRLIST)
200    {
201        orgtype = sxe->iter.type;
202        if (sxe->iter.type == SXE_ITER_NONE) {
203            sxe->iter.type = SXE_ITER_CHILD;
204        }
205        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
206        sxe->iter.type = orgtype;
207    }
208
209    if (sxe->iter.type == SXE_ITER_ELEMENT) {
210        orgnode = sxe_find_element_by_name(sxe, node, sxe->iter.name TSRMLS_CC);
211        if (!orgnode) {
212            return NULL;
213        }
214        node = orgnode->children;
215    }
216
217    while (node) {
218        SKIP_TEXT(node)
219        if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
220            if (!xmlStrcmp(node->name, (xmlChar *)*name)) {
221                if (1||retnode)
222                {
223                    *type = SXE_ITER_ELEMENT;
224                    return orgnode;
225                }
226                retnode = node;
227            }
228        }
229next_iter:
230        node = node->next;
231    }
232
233    if (retnode)
234    {
235        *type = SXE_ITER_NONE;
236        *name = NULL;
237        return retnode;
238    }
239
240    return NULL;
241}
242/* }}} */
243
244/* {{{ sxe_prop_dim_read()
245 */
246static zval *sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type, zval *rv TSRMLS_DC)
247{
248    php_sxe_object *sxe;
249    char           *name;
250    xmlNodePtr      node;
251    xmlAttrPtr      attr = NULL;
252    zval            tmp_zv;
253    int             nodendx = 0;
254    int             test = 0;
255
256    sxe = Z_SXEOBJ_P(object);
257
258    if (!member || Z_TYPE_P(member) == IS_LONG) {
259        if (sxe->iter.type != SXE_ITER_ATTRLIST) {
260            attribs = 0;
261            elements = 1;
262        } else if (!member) {
263            /* This happens when the user did: $sxe[]->foo = $value */
264            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
265            return NULL;
266        }
267        name = NULL;
268    } else {
269        if (Z_TYPE_P(member) != IS_STRING) {
270            tmp_zv = *member;
271            zval_copy_ctor(&tmp_zv);
272            member = &tmp_zv;
273            convert_to_string(member);
274        }
275        name = Z_STRVAL_P(member);
276    }
277
278    GET_NODE(sxe, node);
279
280    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
281        attribs = 1;
282        elements = 0;
283        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
284        attr = (xmlAttrPtr)node;
285        test = sxe->iter.name != NULL;
286    } else if (sxe->iter.type != SXE_ITER_CHILD) {
287        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
288        attr = node ? node->properties : NULL;
289        test = 0;
290        if (!member && node && node->parent &&
291            node->parent->type == XML_DOCUMENT_NODE) {
292            /* This happens when the user did: $sxe[]->foo = $value */
293            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
294            return NULL;
295        }
296    }
297
298    ZVAL_UNDEF(rv);
299
300    if (node) {
301        if (attribs) {
302            if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) {
303                if (Z_TYPE_P(member) == IS_LONG) {
304                    while (attr && nodendx <= Z_LVAL_P(member)) {
305                        if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
306                            if (nodendx == Z_LVAL_P(member)) {
307                                _node_as_zval(sxe, (xmlNodePtr) attr, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
308                                break;
309                            }
310                            nodendx++;
311                        }
312                        attr = attr->next;
313                    }
314                } else {
315                    while (attr) {
316                        if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
317                            _node_as_zval(sxe, (xmlNodePtr) attr, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
318                            break;
319                        }
320                        attr = attr->next;
321                    }
322                }
323            }
324        }
325
326        if (elements) {
327            if (!sxe->node) {
328                php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC);
329            }
330            if (!member || Z_TYPE_P(member) == IS_LONG) {
331                zend_long cnt = 0;
332                xmlNodePtr mynode = node;
333
334                if (sxe->iter.type == SXE_ITER_CHILD) {
335                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
336                }
337                if (sxe->iter.type == SXE_ITER_NONE) {
338                    if (member && Z_LVAL_P(member) > 0) {
339                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %pd when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
340                    }
341                } else if (member) {
342                    node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
343                } else {
344                    node = NULL;
345                }
346                if (node) {
347                    _node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
348                } else if (type == BP_VAR_W || type == BP_VAR_RW) {
349                    if (member && cnt < Z_LVAL_P(member)) {
350                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %pd when only %pd such elements exist", mynode->name, Z_LVAL_P(member), cnt);
351                    }
352                    node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
353                    _node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
354                }
355            } else {
356#if SXE_ELEMENT_BY_NAME
357                int newtype;
358
359                GET_NODE(sxe, node);
360                node = sxe_get_element_by_name(sxe, node, &name, &newtype TSRMLS_CC);
361                if (node) {
362                    _node_as_zval(sxe, node, rv, newtype, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
363                }
364#else
365                _node_as_zval(sxe, node, rv, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
366#endif
367            }
368        }
369    }
370
371    if (member == &tmp_zv) {
372        zval_dtor(&tmp_zv);
373    }
374
375    if (Z_ISUNDEF_P(rv)) {
376        ZVAL_COPY_VALUE(rv, &EG(uninitialized_zval));
377    }
378
379    return rv;
380}
381/* }}} */
382
383/* {{{ sxe_property_read()
384 */
385static zval *sxe_property_read(zval *object, zval *member, int type, void **cache_slot, zval *rv TSRMLS_DC)
386{
387    return sxe_prop_dim_read(object, member, 1, 0, type, rv TSRMLS_CC);
388}
389/* }}} */
390
391/* {{{ sxe_dimension_read()
392 */
393static zval *sxe_dimension_read(zval *object, zval *offset, int type, zval *rv TSRMLS_DC)
394{
395    return sxe_prop_dim_read(object, offset, 0, 1, type, rv TSRMLS_CC);
396}
397/* }}} */
398
399/* {{{ change_node_zval()
400 */
401static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC)
402{
403    zval value_copy;
404    xmlChar *buffer;
405    int buffer_len;
406
407    if (!value)
408    {
409        xmlNodeSetContentLen(node, (xmlChar *)"", 0);
410        return;
411    }
412    switch (Z_TYPE_P(value)) {
413        case IS_LONG:
414        case IS_FALSE:
415        case IS_TRUE:
416        case IS_DOUBLE:
417        case IS_NULL:
418            if (Z_REFCOUNT_P(value) > 1) {
419                value_copy = *value;
420                zval_copy_ctor(&value_copy);
421                value = &value_copy;
422            }
423            convert_to_string(value);
424            /* break missing intentionally */
425        case IS_STRING:
426            buffer = xmlEncodeEntitiesReentrant(node->doc, (xmlChar *)Z_STRVAL_P(value));
427            buffer_len = xmlStrlen(buffer);
428            /* check for NULL buffer in case of memory error in xmlEncodeEntitiesReentrant */
429            if (buffer) {
430                xmlNodeSetContentLen(node, buffer, buffer_len);
431                xmlFree(buffer);
432            }
433            if (value == &value_copy) {
434                zval_dtor(value);
435            }
436            break;
437        default:
438            php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not possible to assign complex types to nodes");
439            break;
440    }
441}
442/* }}} */
443
444/* {{{ sxe_property_write()
445 */
446static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode TSRMLS_DC)
447{
448    php_sxe_object *sxe;
449    xmlNodePtr      node;
450    xmlNodePtr      newnode = NULL;
451    xmlNodePtr      mynode;
452    xmlNodePtr      tempnode;
453    xmlAttrPtr      attr = NULL;
454    int             counter = 0;
455    int             is_attr = 0;
456    int             nodendx = 0;
457    int             test = 0;
458    int             new_value = 0;
459    zend_long            cnt = 0;
460    int             retval = SUCCESS;
461    zval            tmp_zv, trim_zv, zval_copy;
462
463    sxe = Z_SXEOBJ_P(object);
464
465    if (!member || Z_TYPE_P(member) == IS_LONG) {
466        if (sxe->iter.type != SXE_ITER_ATTRLIST) {
467            attribs = 0;
468            elements = 1;
469        } else if (!member) {
470            /* This happens when the user did: $sxe[] = $value
471             * and could also be E_PARSE, but we use this only during parsing
472             * and this is during runtime.
473             */
474            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
475            return FAILURE;
476        }
477    } else {
478        if (Z_TYPE_P(member) != IS_STRING) {
479            trim_zv = *member;
480            zval_copy_ctor(&trim_zv);
481            convert_to_string(&trim_zv);
482            php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC);
483            zval_dtor(&trim_zv);
484            member = &tmp_zv;
485        }
486
487        if (!Z_STRLEN_P(member)) {
488            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element");
489            if (member == &tmp_zv) {
490                zval_dtor(&tmp_zv);
491            }
492            return FAILURE;
493        }
494    }
495
496    GET_NODE(sxe, node);
497
498    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
499        attribs = 1;
500        elements = 0;
501        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
502        attr = (xmlAttrPtr)node;
503        test = sxe->iter.name != NULL;
504    } else if (sxe->iter.type != SXE_ITER_CHILD) {
505        mynode = node;
506        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
507        attr = node ? node->properties : NULL;
508        test = 0;
509        if (!member && node && node->parent &&
510            node->parent->type == XML_DOCUMENT_NODE) {
511            /* This happens when the user did: $sxe[] = $value
512             * and could also be E_PARSE, but we use this only during parsing
513             * and this is during runtime.
514             */
515            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
516            return FAILURE;
517        }
518        if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) {
519            node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL);
520            attr = node->properties;
521        }
522    }
523
524    mynode = node;
525
526    if (value) {
527        switch (Z_TYPE_P(value)) {
528            case IS_LONG:
529            case IS_FALSE:
530            case IS_TRUE:
531            case IS_DOUBLE:
532            case IS_NULL:
533                if (Z_TYPE_P(value) != IS_STRING) {
534                    ZVAL_DUP(&zval_copy, value);
535                    value = &zval_copy;
536                    convert_to_string(value);
537                    new_value = 1;
538                }
539                break;
540            case IS_STRING:
541                break;
542            case IS_OBJECT:
543                if (Z_OBJCE_P(value) == sxe_class_entry) {
544                    //???
545                    value = sxe_get_value(value, &zval_copy TSRMLS_CC);
546                    //INIT_PZVAL(value);
547                    new_value = 1;
548                    break;
549                }
550                /* break is missing intentionally */
551            default:
552                if (member == &tmp_zv) {
553                    zval_dtor(&tmp_zv);
554                }
555                zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties");
556                return FAILURE;
557        }
558    }
559
560    if (node) {
561        if (attribs) {
562            if (Z_TYPE_P(member) == IS_LONG) {
563                while (attr && nodendx <= Z_LVAL_P(member)) {
564                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
565                        if (nodendx == Z_LVAL_P(member)) {
566                            is_attr = 1;
567                            ++counter;
568                            break;
569                        }
570                        nodendx++;
571                    }
572                    attr = attr->next;
573                }
574            } else {
575                while (attr) {
576                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
577                        is_attr = 1;
578                        ++counter;
579                        break;
580                    }
581                    attr = attr->next;
582                }
583            }
584
585        }
586
587        if (elements) {
588            if (!member || Z_TYPE_P(member) == IS_LONG) {
589                if (node->type == XML_ATTRIBUTE_NODE) {
590                    php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create duplicate attribute");
591                    return FAILURE;
592                }
593
594                if (sxe->iter.type == SXE_ITER_NONE) {
595                    newnode = node;
596                    ++counter;
597                    if (member && Z_LVAL_P(member) > 0) {
598                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %pd when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
599                        retval = FAILURE;
600                    }
601                } else if (member) {
602                    newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
603                    if (newnode) {
604                        ++counter;
605                    }
606                }
607            } else {
608                node = node->children;
609                while (node) {
610                    SKIP_TEXT(node);
611
612                    if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
613                        newnode = node;
614                        ++counter;
615                    }
616
617next_iter:
618                    node = node->next;
619                }
620            }
621        }
622
623        if (counter == 1) {
624            if (is_attr) {
625                newnode = (xmlNodePtr) attr;
626            }
627            if (value) {
628                while ((tempnode = (xmlNodePtr) newnode->children)) {
629                    xmlUnlinkNode(tempnode);
630                    php_libxml_node_free_resource((xmlNodePtr) tempnode TSRMLS_CC);
631                }
632                change_node_zval(newnode, value TSRMLS_CC);
633            }
634        } else if (counter > 1) {
635            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)");
636            retval = FAILURE;
637        } else if (elements) {
638            if (!node) {
639                if (!member || Z_TYPE_P(member) == IS_LONG) {
640                    newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
641                } else {
642                    newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
643                }
644            } else if (!member || Z_TYPE_P(member) == IS_LONG) {
645                if (member && cnt < Z_LVAL_P(member)) {
646                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %pd when only %pd such elements exist", mynode->name, Z_LVAL_P(member), cnt);
647                    retval = FAILURE;
648                }
649                newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
650            }
651        } else if (attribs) {
652            if (Z_TYPE_P(member) == IS_LONG) {
653                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change attribute number %pd when only %d attributes exist", Z_LVAL_P(member), nodendx);
654                retval = FAILURE;
655            } else {
656                newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
657            }
658        }
659    }
660
661    if (member == &tmp_zv) {
662        zval_dtor(&tmp_zv);
663    }
664    if (pnewnode) {
665        *pnewnode = newnode;
666    }
667    if (new_value) {
668        zval_ptr_dtor(value);
669    }
670    return retval;
671}
672/* }}} */
673
674/* {{{ sxe_property_write()
675 */
676static void sxe_property_write(zval *object, zval *member, zval *value, void **cache_slot TSRMLS_DC)
677{
678    sxe_prop_dim_write(object, member, value, 1, 0, NULL TSRMLS_CC);
679}
680/* }}} */
681
682/* {{{ sxe_dimension_write()
683 */
684static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_DC)
685{
686    sxe_prop_dim_write(object, offset, value, 0, 1, NULL TSRMLS_CC);
687}
688/* }}} */
689
690static zval *sxe_property_get_adr(zval *object, zval *member, int fetch_type, void **cache_slot TSRMLS_DC) /* {{{ */
691{
692    php_sxe_object *sxe;
693    xmlNodePtr      node;
694    zval            ret;
695    char           *name;
696    SXE_ITER        type;
697
698    sxe = Z_SXEOBJ_P(object);
699
700    GET_NODE(sxe, node);
701    convert_to_string(member);
702    name = Z_STRVAL_P(member);
703    node = sxe_get_element_by_name(sxe, node, &name, &type TSRMLS_CC);
704    if (node) {
705        return NULL;
706    }
707    if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node TSRMLS_CC) != SUCCESS) {
708        return NULL;
709    }
710    type = SXE_ITER_NONE;
711    name = NULL;
712
713    _node_as_zval(sxe, node, &ret, type, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
714
715    sxe = Z_SXEOBJ_P(&ret);
716    if (!Z_ISUNDEF(sxe->tmp)) {
717        zval_ptr_dtor(&sxe->tmp);
718    }
719
720    ZVAL_COPY_VALUE(&sxe->tmp, &ret);
721    //???? Z_SET_ISREF_P(return_value);
722
723    return &sxe->tmp;
724}
725/* }}} */
726
727/* {{{ sxe_prop_dim_exists()
728 */
729static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs TSRMLS_DC)
730{
731    php_sxe_object *sxe;
732    xmlNodePtr      node;
733    xmlAttrPtr      attr = NULL;
734    int             exists = 0;
735    int             test = 0;
736    zval            tmp_zv;
737
738    if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
739        tmp_zv = *member;
740        zval_copy_ctor(&tmp_zv);
741        member = &tmp_zv;
742        convert_to_string(member);
743    }
744
745    sxe = Z_SXEOBJ_P(object);
746
747    GET_NODE(sxe, node);
748
749    if (Z_TYPE_P(member) == IS_LONG) {
750        if (sxe->iter.type != SXE_ITER_ATTRLIST) {
751            attribs = 0;
752            elements = 1;
753            if (sxe->iter.type == SXE_ITER_CHILD) {
754                node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
755            }
756        }
757    }
758
759    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
760        attribs = 1;
761        elements = 0;
762        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
763        attr = (xmlAttrPtr)node;
764        test = sxe->iter.name != NULL;
765    } else if (sxe->iter.type != SXE_ITER_CHILD) {
766        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
767        attr = node ? node->properties : NULL;
768        test = 0;
769    }
770
771    if (node) {
772        if (attribs) {
773            if (Z_TYPE_P(member) == IS_LONG) {
774                int nodendx = 0;
775
776                while (attr && nodendx <= Z_LVAL_P(member)) {
777                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
778                        if (nodendx == Z_LVAL_P(member)) {
779                            exists = 1;
780                            break;
781                        }
782                        nodendx++;
783                    }
784                    attr = attr->next;
785                }
786            } else {
787                while (attr) {
788                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
789                        exists = 1;
790                        break;
791                    }
792
793                    attr = attr->next;
794                }
795            }
796            if (exists && check_empty == 1 &&
797                (!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, "0")) ) {
798                /* Attribute with no content in it's text node */
799                exists = 0;
800            }
801        }
802
803        if (elements) {
804            if (Z_TYPE_P(member) == IS_LONG) {
805                if (sxe->iter.type == SXE_ITER_CHILD) {
806                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
807                }
808                node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
809            }
810            else {
811                node = node->children;
812                while (node) {
813                    xmlNodePtr nnext;
814                    nnext = node->next;
815                    if ((node->type == XML_ELEMENT_NODE) && !xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
816                        break;
817                    }
818                    node = nnext;
819                }
820            }
821            if (node) {
822                exists = 1;
823                if (check_empty == 1 &&
824                    (!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
825                     (!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, "0")))) ) {
826                    exists = 0;
827                }
828            }
829        }
830    }
831
832    if (member == &tmp_zv) {
833        zval_dtor(&tmp_zv);
834    }
835
836    return exists;
837}
838/* }}} */
839
840/* {{{ sxe_property_exists()
841 */
842static int sxe_property_exists(zval *object, zval *member, int check_empty, void **cache_slot TSRMLS_DC)
843{
844    return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC);
845}
846/* }}} */
847
848/* {{{ sxe_property_exists()
849 */
850static int sxe_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
851{
852    return sxe_prop_dim_exists(object, member, check_empty, 0, 1 TSRMLS_CC);
853}
854/* }}} */
855
856/* {{{ sxe_prop_dim_delete()
857 */
858static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs TSRMLS_DC)
859{
860    php_sxe_object *sxe;
861    xmlNodePtr      node;
862    xmlNodePtr      nnext;
863    xmlAttrPtr      attr = NULL;
864    xmlAttrPtr      anext;
865    zval            tmp_zv;
866    int             test = 0;
867
868    if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
869        tmp_zv = *member;
870        zval_copy_ctor(&tmp_zv);
871        member = &tmp_zv;
872        convert_to_string(member);
873    }
874
875    sxe = Z_SXEOBJ_P(object);
876
877    GET_NODE(sxe, node);
878
879    if (Z_TYPE_P(member) == IS_LONG) {
880        if (sxe->iter.type != SXE_ITER_ATTRLIST) {
881            attribs = 0;
882            elements = 1;
883            if (sxe->iter.type == SXE_ITER_CHILD) {
884                node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
885            }
886        }
887    }
888
889    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
890        attribs = 1;
891        elements = 0;
892        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
893        attr = (xmlAttrPtr)node;
894        test = sxe->iter.name != NULL;
895    } else if (sxe->iter.type != SXE_ITER_CHILD) {
896        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
897        attr = node ? node->properties : NULL;
898        test = 0;
899    }
900
901    if (node) {
902        if (attribs) {
903            if (Z_TYPE_P(member) == IS_LONG) {
904                int nodendx = 0;
905
906                while (attr && nodendx <= Z_LVAL_P(member)) {
907                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
908                        if (nodendx == Z_LVAL_P(member)) {
909                            xmlUnlinkNode((xmlNodePtr) attr);
910                            php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
911                            break;
912                        }
913                        nodendx++;
914                    }
915                    attr = attr->next;
916                }
917            } else {
918                while (attr) {
919                    anext = attr->next;
920                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
921                        xmlUnlinkNode((xmlNodePtr) attr);
922                        php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
923                        break;
924                    }
925                    attr = anext;
926                }
927            }
928        }
929
930        if (elements) {
931            if (Z_TYPE_P(member) == IS_LONG) {
932                if (sxe->iter.type == SXE_ITER_CHILD) {
933                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
934                }
935                node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
936                if (node) {
937                    xmlUnlinkNode(node);
938                    php_libxml_node_free_resource(node TSRMLS_CC);
939                }
940            } else {
941                node = node->children;
942                while (node) {
943                    nnext = node->next;
944
945                    SKIP_TEXT(node);
946
947                    if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
948                        xmlUnlinkNode(node);
949                        php_libxml_node_free_resource(node TSRMLS_CC);
950                    }
951
952next_iter:
953                    node = nnext;
954                }
955            }
956        }
957    }
958
959    if (member == &tmp_zv) {
960        zval_dtor(&tmp_zv);
961    }
962}
963/* }}} */
964
965/* {{{ sxe_property_delete()
966 */
967static void sxe_property_delete(zval *object, zval *member, void **cache_slot TSRMLS_DC)
968{
969    sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC);
970}
971/* }}} */
972
973/* {{{ sxe_dimension_unset()
974 */
975static void sxe_dimension_delete(zval *object, zval *offset TSRMLS_DC)
976{
977    sxe_prop_dim_delete(object, offset, 0, 1 TSRMLS_CC);
978}
979/* }}} */
980
981static inline zend_string *sxe_xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine TSRMLS_DC) /* {{{ */
982{
983    xmlChar *tmp = xmlNodeListGetString(doc, list, inLine);
984    zend_string *res;
985
986    if (tmp) {
987        res = zend_string_init((char*)tmp, strlen((char *)tmp), 0);
988        xmlFree(tmp);
989    } else {
990        res = STR_EMPTY_ALLOC();
991    }
992
993    return res;
994}
995/* }}} */
996
997/* {{{ _get_base_node_value()
998 */
999static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval *value, xmlChar *nsprefix, int isprefix TSRMLS_DC)
1000{
1001    php_sxe_object *subnode;
1002    xmlChar        *contents;
1003
1004    if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
1005        contents = xmlNodeListGetString(node->doc, node->children, 1);
1006        if (contents) {
1007            ZVAL_STRING(value, (char *)contents);
1008            xmlFree(contents);
1009        }
1010    } else {
1011        subnode = php_sxe_object_new(sxe_ref->zo.ce TSRMLS_CC);
1012        subnode->document = sxe_ref->document;
1013        subnode->document->refcount++;
1014        if (nsprefix && *nsprefix) {
1015            subnode->iter.nsprefix = xmlStrdup((xmlChar *)nsprefix);
1016            subnode->iter.isprefix = isprefix;
1017        }
1018        php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
1019
1020        ZVAL_OBJ(value, &subnode->zo);
1021        /*zval_add_ref(value);*/
1022    }
1023}
1024/* }}} */
1025
1026static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value TSRMLS_DC) /* {{{ */
1027{
1028    zval  *data_ptr;
1029    zval  newptr;
1030
1031    if ((data_ptr = zend_hash_str_find(rv, name, namelen)) != NULL) {
1032        if (Z_TYPE_P(data_ptr) == IS_ARRAY) {
1033            zend_hash_next_index_insert(Z_ARRVAL_P(data_ptr), value);
1034        } else {
1035            array_init(&newptr);
1036
1037            if (Z_REFCOUNTED_P(data_ptr)) {
1038                Z_ADDREF_P(data_ptr);
1039            }
1040            zend_hash_next_index_insert(Z_ARRVAL(newptr), data_ptr);
1041            zend_hash_next_index_insert(Z_ARRVAL(newptr), value);
1042
1043            zend_hash_str_update(rv, name, namelen, &newptr);
1044        }
1045    } else {
1046        zend_hash_str_update(rv, name, namelen, value);
1047    }
1048}
1049/* }}} */
1050
1051static HashTable *sxe_get_prop_hash(zval *object, int is_debug TSRMLS_DC) /* {{{ */
1052{
1053    zval            value;
1054    zval            zattr;
1055    HashTable       *rv;
1056    php_sxe_object  *sxe;
1057    char            *name;
1058    xmlNodePtr       node;
1059    xmlAttrPtr       attr;
1060    int              namelen;
1061    int              test;
1062    char             use_iter;
1063    zval             iter_data;
1064
1065    use_iter = 0;
1066
1067    sxe = Z_SXEOBJ_P(object);
1068
1069    if (is_debug) {
1070        ALLOC_HASHTABLE(rv);
1071        zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1072    } else if (sxe->properties) {
1073        zend_hash_clean(sxe->properties);
1074        rv = sxe->properties;
1075    } else {
1076        ALLOC_HASHTABLE(rv);
1077        zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1078        sxe->properties = rv;
1079    }
1080
1081    GET_NODE(sxe, node);
1082    if (!node) {
1083        return rv;
1084    }
1085    if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
1086        if (sxe->iter.type == SXE_ITER_ELEMENT) {
1087            node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1088        }
1089        if (!node || node->type != XML_ENTITY_DECL) {
1090            attr = node ? (xmlAttrPtr)node->properties : NULL;
1091            ZVAL_UNDEF(&zattr);
1092            test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1093            while (attr) {
1094                if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1095                    ZVAL_STR(&value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1 TSRMLS_CC));
1096                    namelen = xmlStrlen(attr->name);
1097                    if (Z_ISUNDEF(zattr)) {
1098                        array_init(&zattr);
1099                        sxe_properties_add(rv, "@attributes", sizeof("@attributes") - 1, &zattr TSRMLS_CC);
1100                    }
1101                    add_assoc_zval_ex(&zattr, (char*)attr->name, namelen, &value);
1102                }
1103                attr = attr->next;
1104            }
1105        }
1106    }
1107
1108    GET_NODE(sxe, node);
1109    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1110
1111    if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1112        if (node->type == XML_ATTRIBUTE_NODE) {
1113            ZVAL_STR(&value, sxe_xmlNodeListGetString(node->doc, node->children, 1 TSRMLS_CC));
1114            zend_hash_next_index_insert(rv, &value);
1115            node = NULL;
1116        } else if (sxe->iter.type != SXE_ITER_CHILD) {
1117
1118            if ( !node->children || !node->parent || !node->next || node->children->next || node->children->children || node->parent->children == node->parent->last ) {
1119                node = node->children;
1120            } else {
1121                ZVAL_COPY_VALUE(&iter_data, &sxe->iter.data);
1122                ZVAL_UNDEF(&sxe->iter.data);
1123
1124                node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1125
1126                use_iter = 1;
1127            }
1128        }
1129
1130        while (node) {
1131            if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1132                SKIP_TEXT(node);
1133            } else {
1134                if (node->type == XML_TEXT_NODE) {
1135                    const xmlChar *cur = node->content;
1136
1137                    if (*cur != 0) {
1138                        ZVAL_STR(&value, sxe_xmlNodeListGetString(node->doc, node, 1 TSRMLS_CC));
1139                        zend_hash_next_index_insert(rv, &value);
1140                    }
1141                    goto next_iter;
1142                }
1143            }
1144
1145            if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1146                goto next_iter;
1147            }
1148
1149            name = (char *) node->name;
1150            if (!name) {
1151                goto next_iter;
1152            } else {
1153                namelen = xmlStrlen(node->name);
1154            }
1155
1156            _get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
1157
1158            if ( use_iter ) {
1159                zend_hash_next_index_insert(rv, &value);
1160            } else {
1161                sxe_properties_add(rv, name, namelen, &value TSRMLS_CC);
1162            }
1163next_iter:
1164            if (use_iter) {
1165                node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1166            } else {
1167                node = node->next;
1168            }
1169        }
1170    }
1171
1172    if (use_iter) {
1173        if (!Z_ISUNDEF(sxe->iter.data)) {
1174            zval_ptr_dtor(&sxe->iter.data);
1175        }
1176        ZVAL_COPY_VALUE(&sxe->iter.data, &iter_data);
1177    }
1178
1179    return rv;
1180}
1181/* }}} */
1182
1183static HashTable *sxe_get_gc(zval *object, zval **table, int *n TSRMLS_DC) /* {{{ */ {
1184    php_sxe_object *sxe;
1185    sxe = Z_SXEOBJ_P(object);
1186
1187    *table = NULL;
1188    *n = 0;
1189    return sxe->properties;
1190}
1191/* }}} */
1192
1193static HashTable *sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */
1194{
1195    return sxe_get_prop_hash(object, 0 TSRMLS_CC);
1196}
1197/* }}} */
1198
1199static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
1200{
1201    *is_temp = 1;
1202    return sxe_get_prop_hash(object, 1 TSRMLS_CC);
1203}
1204/* }}} */
1205
1206static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */
1207{
1208    php_sxe_object *sxe1;
1209    php_sxe_object *sxe2;
1210
1211    sxe1 = Z_SXEOBJ_P(object1);
1212    sxe2 = Z_SXEOBJ_P(object2);
1213
1214    if (sxe1->node == NULL) {
1215        if (sxe2->node) {
1216            return 1;
1217        } else if (sxe1->document->ptr == sxe2->document->ptr) {
1218            return 0;
1219        }
1220    } else {
1221        return !(sxe1->node == sxe2->node);
1222    }
1223    return 1;
1224}
1225/* }}} */
1226
1227/* {{{ proto array SimpleXMLElement::xpath(string path)
1228   Runs XPath query on the XML data */
1229SXE_METHOD(xpath)
1230{
1231    php_sxe_object    *sxe;
1232    zval               value;
1233    char              *query;
1234    size_t                query_len;
1235    int                i;
1236    int                nsnbr = 0;
1237    xmlNsPtr          *ns = NULL;
1238    xmlXPathObjectPtr  retval;
1239    xmlNodeSetPtr      result;
1240    xmlNodePtr         nodeptr;
1241
1242    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
1243        return;
1244    }
1245
1246    sxe = Z_SXEOBJ_P(getThis());
1247
1248    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1249        return; /* attributes don't have attributes */
1250    }
1251
1252    if (!sxe->xpath) {
1253        sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1254    }
1255    if (!sxe->node) {
1256        php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1257        if (!sxe->node) {
1258            RETURN_FALSE;
1259        }
1260    }
1261
1262    nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC);
1263
1264    sxe->xpath->node = nodeptr;
1265
1266    ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
1267    if (ns != NULL) {
1268        while (ns[nsnbr] != NULL) {
1269            nsnbr++;
1270        }
1271    }
1272
1273    sxe->xpath->namespaces = ns;
1274    sxe->xpath->nsNr = nsnbr;
1275
1276    retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
1277    if (ns != NULL) {
1278        xmlFree(ns);
1279        sxe->xpath->namespaces = NULL;
1280        sxe->xpath->nsNr = 0;
1281    }
1282
1283    if (!retval) {
1284        RETURN_FALSE;
1285    }
1286
1287    result = retval->nodesetval;
1288
1289    array_init(return_value);
1290
1291    if (result != NULL) {
1292        for (i = 0; i < result->nodeNr; ++i) {
1293            nodeptr = result->nodeTab[i];
1294            if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
1295                /**
1296                 * Detect the case where the last selector is text(), simplexml
1297                 * always accesses the text() child by default, therefore we assign
1298                 * to the parent node.
1299                 */
1300                if (nodeptr->type == XML_TEXT_NODE) {
1301                    _node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1302                } else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
1303                    _node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC);
1304                } else {
1305                    _node_as_zval(sxe, nodeptr, &value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1306                }
1307
1308                add_next_index_zval(return_value, &value);
1309            }
1310        }
1311    }
1312
1313    xmlXPathFreeObject(retval);
1314}
1315/* }}} */
1316
1317/* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
1318   Creates a prefix/ns context for the next XPath query */
1319SXE_METHOD(registerXPathNamespace)
1320{
1321    php_sxe_object    *sxe;
1322    size_t prefix_len, ns_uri_len;
1323    char *prefix, *ns_uri;
1324
1325    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
1326        return;
1327    }
1328
1329    sxe = Z_SXEOBJ_P(getThis());
1330    if (!sxe->xpath) {
1331        sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1332    }
1333
1334    if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
1335        RETURN_FALSE
1336    }
1337    RETURN_TRUE;
1338}
1339
1340/* }}} */
1341
1342/* {{{ proto string SimpleXMLElement::asXML([string filename])
1343   Return a well-formed XML string based on SimpleXML element */
1344SXE_METHOD(asXML)
1345{
1346    php_sxe_object     *sxe;
1347    xmlNodePtr          node;
1348    xmlOutputBufferPtr  outbuf;
1349    xmlChar            *strval;
1350    int                 strval_len;
1351    char               *filename;
1352    size_t                 filename_len;
1353
1354    if (ZEND_NUM_ARGS() > 1) {
1355        RETURN_FALSE;
1356    }
1357
1358    if (ZEND_NUM_ARGS() == 1) {
1359        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
1360            RETURN_FALSE;
1361        }
1362
1363        sxe = Z_SXEOBJ_P(getThis());
1364        GET_NODE(sxe, node);
1365        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1366
1367        if (node) {
1368            if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1369                int bytes;
1370                bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
1371                if (bytes == -1) {
1372                    RETURN_FALSE;
1373                } else {
1374                    RETURN_TRUE;
1375                }
1376            } else {
1377                outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
1378
1379                if (outbuf == NULL) {
1380                    RETURN_FALSE;
1381                }
1382
1383                xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
1384                xmlOutputBufferClose(outbuf);
1385                RETURN_TRUE;
1386            }
1387        } else {
1388            RETURN_FALSE;
1389        }
1390    }
1391
1392    sxe = Z_SXEOBJ_P(getThis());
1393    GET_NODE(sxe, node);
1394    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1395
1396    if (node) {
1397        if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1398            xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding);
1399            RETVAL_STRINGL((char *)strval, strval_len);
1400            xmlFree(strval);
1401        } else {
1402            /* Should we be passing encoding information instead of NULL? */
1403            outbuf = xmlAllocOutputBuffer(NULL);
1404
1405            if (outbuf == NULL) {
1406                RETURN_FALSE;
1407            }
1408
1409            xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
1410            xmlOutputBufferFlush(outbuf);
1411#ifdef LIBXML2_NEW_BUFFER
1412            RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf), xmlOutputBufferGetSize(outbuf));
1413#else
1414            RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use);
1415#endif
1416            xmlOutputBufferClose(outbuf);
1417        }
1418    } else {
1419        RETVAL_FALSE;
1420    }
1421}
1422/* }}} */
1423
1424#define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1425
1426static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1427{
1428    char *prefix = SXE_NS_PREFIX(ns);
1429    if (zend_hash_str_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix)) == 0) {
1430        add_assoc_string(return_value, prefix, (char*)ns->href);
1431    }
1432}
1433/* }}} */
1434
1435static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1436{
1437    xmlAttrPtr  attr;
1438
1439    if (node->ns) {
1440        sxe_add_namespace_name(return_value, node->ns);
1441    }
1442
1443    attr = node->properties;
1444    while (attr) {
1445        if (attr->ns) {
1446            sxe_add_namespace_name(return_value, attr->ns);
1447        }
1448        attr = attr->next;
1449    }
1450
1451    if (recursive) {
1452        node = node->children;
1453        while (node) {
1454            if (node->type == XML_ELEMENT_NODE) {
1455                sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1456            }
1457            node = node->next;
1458        }
1459    }
1460} /* }}} */
1461
1462/* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1463   Return all namespaces in use */
1464SXE_METHOD(getNamespaces)
1465{
1466    zend_bool           recursive = 0;
1467    php_sxe_object     *sxe;
1468    xmlNodePtr          node;
1469
1470    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1471        return;
1472    }
1473
1474    array_init(return_value);
1475
1476    sxe = Z_SXEOBJ_P(getThis());
1477    GET_NODE(sxe, node);
1478    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1479
1480    if (node) {
1481        if (node->type == XML_ELEMENT_NODE) {
1482            sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1483        } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1484            sxe_add_namespace_name(return_value, node->ns);
1485        }
1486    }
1487}
1488/* }}} */
1489
1490static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1491{
1492    xmlNsPtr ns;
1493
1494    if (node->type == XML_ELEMENT_NODE) {
1495        ns = node->nsDef;
1496        while (ns != NULL) {
1497            sxe_add_namespace_name(return_value, ns);
1498            ns = ns->next;
1499        }
1500        if (recursive) {
1501            node = node->children;
1502            while (node) {
1503                sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1504                node = node->next;
1505            }
1506        }
1507    }
1508}
1509/* }}} */
1510
1511/* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive [, bool from_root])
1512   Return all namespaces registered with document */
1513SXE_METHOD(getDocNamespaces)
1514{
1515    zend_bool           recursive = 0, from_root = 1;
1516    php_sxe_object     *sxe;
1517    xmlNodePtr          node;
1518
1519    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &recursive, &from_root) == FAILURE) {
1520        return;
1521    }
1522
1523    sxe = Z_SXEOBJ_P(getThis());
1524    if(from_root){
1525        node = xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr);
1526    }else{
1527        GET_NODE(sxe, node);
1528    }
1529
1530    if (node == NULL) {
1531        RETURN_FALSE;
1532    }
1533
1534    array_init(return_value);
1535    sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1536}
1537/* }}} */
1538
1539/* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1540   Finds children of given node */
1541SXE_METHOD(children)
1542{
1543    php_sxe_object *sxe;
1544    char           *nsprefix = NULL;
1545    size_t             nsprefix_len = 0;
1546    xmlNodePtr      node;
1547    zend_bool       isprefix = 0;
1548
1549    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1550        return;
1551    }
1552
1553    sxe = Z_SXEOBJ_P(getThis());
1554
1555    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1556        return; /* attributes don't have attributes */
1557    }
1558
1559    GET_NODE(sxe, node);
1560    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1561
1562    _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1563
1564}
1565/* }}} */
1566
1567/* {{{ proto object SimpleXMLElement::getName()
1568   Finds children of given node */
1569SXE_METHOD(getName)
1570{
1571    php_sxe_object *sxe;
1572    xmlNodePtr      node;
1573    int             namelen;
1574
1575    sxe = Z_SXEOBJ_P(getThis());
1576
1577    GET_NODE(sxe, node);
1578    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1579    if (node) {
1580        namelen = xmlStrlen(node->name);
1581        RETURN_STRINGL((char*)node->name, namelen);
1582    } else {
1583        RETURN_EMPTY_STRING();
1584    }
1585}
1586/* }}} */
1587
1588/* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1589   Identifies an element's attributes */
1590SXE_METHOD(attributes)
1591{
1592    php_sxe_object *sxe;
1593    char           *nsprefix = NULL;
1594    size_t             nsprefix_len = 0;
1595    xmlNodePtr      node;
1596    zend_bool       isprefix = 0;
1597
1598    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1599        return;
1600    }
1601
1602    sxe = Z_SXEOBJ_P(getThis());
1603    GET_NODE(sxe, node);
1604
1605    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1606        return; /* attributes don't have attributes */
1607    }
1608
1609    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1610
1611    _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1612}
1613/* }}} */
1614
1615/* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1616   Add Element with optional namespace information */
1617SXE_METHOD(addChild)
1618{
1619    php_sxe_object *sxe;
1620    char           *qname, *value = NULL, *nsuri = NULL;
1621    size_t             qname_len, value_len = 0, nsuri_len = 0;
1622    xmlNodePtr      node, newnode;
1623    xmlNsPtr        nsptr = NULL;
1624    xmlChar        *localname, *prefix = NULL;
1625
1626    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1627        &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1628        return;
1629    }
1630
1631    if (qname_len == 0) {
1632        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1633        return;
1634    }
1635
1636    sxe = Z_SXEOBJ_P(getThis());
1637    GET_NODE(sxe, node);
1638
1639    if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1640        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1641        return;
1642    }
1643
1644    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1645
1646    if (node == NULL) {
1647        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1648        return;
1649    }
1650
1651    localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1652    if (localname == NULL) {
1653        localname = xmlStrdup((xmlChar *)qname);
1654    }
1655
1656    newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1657
1658    if (nsuri != NULL) {
1659        if (nsuri_len == 0) {
1660            newnode->ns = NULL;
1661            nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1662        } else {
1663            nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1664            if (nsptr == NULL) {
1665                nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1666            }
1667            newnode->ns = nsptr;
1668        }
1669    }
1670
1671    _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
1672
1673    xmlFree(localname);
1674    if (prefix != NULL) {
1675        xmlFree(prefix);
1676    }
1677}
1678/* }}} */
1679
1680/* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1681   Add Attribute with optional namespace information */
1682SXE_METHOD(addAttribute)
1683{
1684    php_sxe_object *sxe;
1685    char           *qname, *value = NULL, *nsuri = NULL;
1686    size_t             qname_len, value_len = 0, nsuri_len = 0;
1687    xmlNodePtr      node;
1688    xmlAttrPtr      attrp = NULL;
1689    xmlNsPtr        nsptr = NULL;
1690    xmlChar        *localname, *prefix = NULL;
1691
1692    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1693        &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1694        return;
1695    }
1696
1697    if (qname_len == 0) {
1698        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
1699        return;
1700    }
1701
1702    sxe = Z_SXEOBJ_P(getThis());
1703    GET_NODE(sxe, node);
1704
1705    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1706
1707    if (node && node->type != XML_ELEMENT_NODE) {
1708        node = node->parent;
1709    }
1710
1711    if (node == NULL) {
1712        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1713        return;
1714    }
1715
1716    localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1717    if (localname == NULL) {
1718        if (nsuri_len > 0) {
1719            if (prefix != NULL) {
1720                xmlFree(prefix);
1721            }
1722            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
1723            return;
1724        }
1725        localname = xmlStrdup((xmlChar *)qname);
1726    }
1727
1728    attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1729    if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1730        xmlFree(localname);
1731        if (prefix != NULL) {
1732            xmlFree(prefix);
1733        }
1734        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1735        return;
1736    }
1737
1738    if (nsuri != NULL) {
1739        nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1740        if (nsptr == NULL) {
1741            nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1742        }
1743    }
1744
1745    attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1746
1747    xmlFree(localname);
1748    if (prefix != NULL) {
1749        xmlFree(prefix);
1750    }
1751}
1752/* }}} */
1753
1754/* {{{ cast_object()
1755 */
1756static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
1757{
1758    if (contents) {
1759        ZVAL_STRINGL(object, contents, strlen(contents));
1760    } else {
1761        ZVAL_NULL(object);
1762    }
1763    //???? Z_SET_REFCOUNT_P(object, 1);
1764    //Z_UNSET_ISREF_P(object);
1765
1766    switch (type) {
1767        case IS_STRING:
1768            convert_to_string(object);
1769            break;
1770        case _IS_BOOL:
1771            convert_to_boolean(object);
1772            break;
1773        case IS_LONG:
1774            convert_to_long(object);
1775            break;
1776        case IS_DOUBLE:
1777            convert_to_double(object);
1778            break;
1779        default:
1780            return FAILURE;
1781    }
1782    return SUCCESS;
1783}
1784/* }}} */
1785
1786/* {{{ sxe_object_cast()
1787 */
1788static int sxe_object_cast_ex(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1789{
1790    php_sxe_object *sxe;
1791    xmlChar        *contents = NULL;
1792    xmlNodePtr      node;
1793    int rv;
1794    HashTable      *prop_hash;
1795
1796    sxe = Z_SXEOBJ_P(readobj);
1797
1798    if (type == _IS_BOOL) {
1799        node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1800        prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
1801        ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
1802        zend_hash_destroy(prop_hash);
1803        efree(prop_hash);
1804        return SUCCESS;
1805    }
1806
1807    if (sxe->iter.type != SXE_ITER_NONE) {
1808        node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1809        if (node) {
1810            contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1811        }
1812    } else {
1813        if (!sxe->node) {
1814            if (sxe->document) {
1815                php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1816            }
1817        }
1818
1819        if (sxe->node && sxe->node->node) {
1820            if (sxe->node->node->children) {
1821                contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1822            }
1823        }
1824    }
1825
1826    if (readobj == writeobj) {
1827        zval_ptr_dtor(readobj);
1828    }
1829
1830    rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
1831
1832    if (contents) {
1833        xmlFree(contents);
1834    }
1835
1836    return rv;
1837}
1838/* }}} */
1839
1840/* Variant of sxe_object_cast_ex that handles overwritten __toString() method */
1841static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1842{
1843    if (type == IS_STRING
1844        && zend_std_cast_object_tostring(readobj, writeobj, IS_STRING TSRMLS_CC) == SUCCESS
1845    ) {
1846        return SUCCESS;
1847    }
1848
1849    return sxe_object_cast_ex(readobj, writeobj, type TSRMLS_CC);
1850}
1851
1852/* {{{ proto object SimpleXMLElement::__toString() U
1853   Returns the string content */
1854SXE_METHOD(__toString)
1855{
1856    zval           result;
1857
1858    if (sxe_object_cast_ex(getThis(), &result, IS_STRING TSRMLS_CC) == SUCCESS) {
1859        RETURN_ZVAL(&result, 0, 0);
1860    } else {
1861        zval_ptr_dtor(&result);
1862        RETURN_EMPTY_STRING();
1863    }
1864}
1865/* }}} */
1866
1867static int php_sxe_count_elements_helper(php_sxe_object *sxe, zend_long *count TSRMLS_DC) /* {{{ */
1868{
1869    xmlNodePtr      node;
1870    zval            data;
1871
1872    *count = 0;
1873
1874    ZVAL_COPY_VALUE(&data, &sxe->iter.data);
1875    ZVAL_UNDEF(&sxe->iter.data);
1876
1877    node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1878
1879    while (node)
1880    {
1881        (*count)++;
1882        node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1883    }
1884
1885    if (!Z_ISUNDEF(sxe->iter.data)) {
1886        zval_ptr_dtor(&sxe->iter.data);
1887    }
1888    ZVAL_COPY_VALUE(&sxe->iter.data, &data);
1889
1890    return SUCCESS;
1891}
1892/* }}} */
1893
1894static int sxe_count_elements(zval *object, zend_long *count TSRMLS_DC) /* {{{ */
1895{
1896    php_sxe_object  *intern;
1897    intern = Z_SXEOBJ_P(object);
1898    if (intern->fptr_count) {
1899        zval rv;
1900        zend_call_method_with_0_params(object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1901        if (!Z_ISUNDEF(rv)) {
1902            if (!Z_ISUNDEF(intern->tmp)) {
1903                zval_ptr_dtor(&intern->tmp);
1904            }
1905            ZVAL_ZVAL(&intern->tmp, &rv, 0, 0);
1906            convert_to_long(&intern->tmp);
1907            *count = (zend_long)Z_LVAL(intern->tmp);
1908            return SUCCESS;
1909        }
1910        return FAILURE;
1911    }
1912    return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
1913}
1914/* }}} */
1915
1916/* {{{ proto int SimpleXMLElement::count()
1917 Get number of child elements */
1918SXE_METHOD(count)
1919{
1920    zend_long count = 0;
1921    php_sxe_object *sxe = Z_SXEOBJ_P(getThis());
1922
1923    if (zend_parse_parameters_none() == FAILURE) {
1924        return;
1925    }
1926
1927    php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
1928
1929    RETURN_LONG(count);
1930}
1931/* }}} */
1932
1933static zval *sxe_get_value(zval *z, zval *rv TSRMLS_DC) /* {{{ */
1934{
1935    if (sxe_object_cast_ex(z, rv, IS_STRING TSRMLS_CC) == FAILURE) {
1936        zend_error(E_ERROR, "Unable to cast node to string");
1937        /* FIXME: Should not be fatal */
1938    }
1939
1940    return rv;
1941}
1942/* }}} */
1943
1944static zend_object_handlers sxe_object_handlers = { /* {{{ */
1945    ZEND_OBJECTS_STORE_HANDLERS,
1946    sxe_property_read,
1947    sxe_property_write,
1948    sxe_dimension_read,
1949    sxe_dimension_write,
1950    sxe_property_get_adr,
1951    sxe_get_value,          /* get */
1952    NULL,
1953    sxe_property_exists,
1954    sxe_property_delete,
1955    sxe_dimension_exists,
1956    sxe_dimension_delete,
1957    sxe_get_properties,
1958    NULL, /* zend_get_std_object_handlers()->get_method,*/
1959    NULL, /* zend_get_std_object_handlers()->call_method,*/
1960    NULL, /* zend_get_std_object_handlers()->get_constructor, */
1961    NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
1962    NULL, /* zend_get_std_object_handlers()->get_class_name,*/
1963    sxe_objects_compare,
1964    sxe_object_cast,
1965    sxe_count_elements,
1966    sxe_get_debug_info,
1967    NULL,
1968    sxe_get_gc
1969};
1970/* }}} */
1971
1972/* {{{ sxe_object_clone()
1973 */
1974static zend_object *
1975sxe_object_clone(zval *object TSRMLS_DC)
1976{
1977    php_sxe_object *sxe = Z_SXEOBJ_P(object);
1978    php_sxe_object *clone;
1979    xmlNodePtr nodep = NULL;
1980    xmlDocPtr docp = NULL;
1981
1982    clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
1983    clone->document = sxe->document;
1984    if (clone->document) {
1985        clone->document->refcount++;
1986        docp = clone->document->ptr;
1987    }
1988
1989    clone->iter.isprefix = sxe->iter.isprefix;
1990    if (sxe->iter.name != NULL) {
1991        clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
1992    }
1993    if (sxe->iter.nsprefix != NULL) {
1994        clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
1995    }
1996    clone->iter.type = sxe->iter.type;
1997
1998    if (sxe->node) {
1999        nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
2000    }
2001
2002    php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
2003
2004    return &clone->zo;
2005}
2006/* }}} */
2007
2008/* {{{ sxe_object_dtor()
2009 */
2010static void sxe_object_dtor(zend_object *object TSRMLS_DC)
2011{
2012    /* dtor required to cleanup iterator related data properly */
2013    php_sxe_object *sxe;
2014
2015    sxe = php_sxe_fetch_object(object);
2016
2017    if (!Z_ISUNDEF(sxe->iter.data)) {
2018        zval_ptr_dtor(&sxe->iter.data);
2019        ZVAL_UNDEF(&sxe->iter.data);
2020    }
2021
2022    if (sxe->iter.name) {
2023        xmlFree(sxe->iter.name);
2024        sxe->iter.name = NULL;
2025    }
2026    if (sxe->iter.nsprefix) {
2027        xmlFree(sxe->iter.nsprefix);
2028        sxe->iter.nsprefix = NULL;
2029    }
2030    if (!Z_ISUNDEF(sxe->tmp)) {
2031        zval_ptr_dtor(&sxe->tmp);
2032        ZVAL_UNDEF(&sxe->tmp);
2033    }
2034}
2035/* }}} */
2036
2037/* {{{ sxe_object_free_storage()
2038 */
2039static void sxe_object_free_storage(zend_object *object TSRMLS_DC)
2040{
2041    php_sxe_object *sxe;
2042
2043    sxe = php_sxe_fetch_object(object);
2044
2045    zend_object_std_dtor(&sxe->zo TSRMLS_CC);
2046
2047    php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
2048
2049    if (sxe->xpath) {
2050        xmlXPathFreeContext(sxe->xpath);
2051    }
2052
2053    if (sxe->properties) {
2054        zend_hash_destroy(sxe->properties);
2055        FREE_HASHTABLE(sxe->properties);
2056    }
2057}
2058/* }}} */
2059
2060/* {{{ php_sxe_object_new()
2061 */
2062static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2063{
2064    php_sxe_object *intern;
2065    zend_class_entry *parent = ce;
2066    int inherited = 0;
2067
2068    intern = ecalloc(1, sizeof(php_sxe_object) + sizeof(zval) * (parent->default_properties_count - 1));
2069
2070    intern->iter.type = SXE_ITER_NONE;
2071    intern->iter.nsprefix = NULL;
2072    intern->iter.name = NULL;
2073    intern->fptr_count = NULL;
2074
2075    zend_object_std_init(&intern->zo, ce TSRMLS_CC);
2076    object_properties_init(&intern->zo, ce);
2077    intern->zo.handlers = &sxe_object_handlers;
2078
2079    while (parent) {
2080        if (parent == sxe_class_entry) {
2081            break;
2082        }
2083
2084        parent = parent->parent;
2085        inherited = 1;
2086    }
2087
2088    if (inherited) {
2089        intern->fptr_count = zend_hash_str_find_ptr(&ce->function_table, "count", sizeof("count") - 1);
2090        if (intern->fptr_count->common.scope == parent) {
2091            intern->fptr_count = NULL;
2092        }
2093    }
2094
2095    return intern;
2096}
2097/* }}} */
2098
2099/* {{{ sxe_object_new()
2100 */
2101PHP_SXE_API zend_object *
2102sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2103{
2104    php_sxe_object    *intern;
2105
2106    intern = php_sxe_object_new(ce TSRMLS_CC);
2107    return &intern->zo;
2108}
2109/* }}} */
2110
2111/* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2112   Load a filename and return a simplexml_element object to allow for processing */
2113PHP_FUNCTION(simplexml_load_file)
2114{
2115    php_sxe_object *sxe;
2116    char           *filename;
2117    size_t             filename_len;
2118    xmlDocPtr       docp;
2119    char           *ns = NULL;
2120    size_t             ns_len = 0;
2121    zend_long            options = 0;
2122    zend_class_entry *ce= sxe_class_entry;
2123    zend_bool       isprefix = 0;
2124
2125    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2126        return;
2127    }
2128
2129    docp = xmlReadFile(filename, NULL, options);
2130
2131    if (!docp) {
2132        RETURN_FALSE;
2133    }
2134
2135    if (!ce) {
2136        ce = sxe_class_entry;
2137    }
2138    sxe = php_sxe_object_new(ce TSRMLS_CC);
2139    sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2140    sxe->iter.isprefix = isprefix;
2141    php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2142    php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2143
2144    ZVAL_OBJ(return_value, &sxe->zo);
2145}
2146/* }}} */
2147
2148/* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2149   Load a string and return a simplexml_element object to allow for processing */
2150PHP_FUNCTION(simplexml_load_string)
2151{
2152    php_sxe_object *sxe;
2153    char           *data;
2154    size_t             data_len;
2155    xmlDocPtr       docp;
2156    char           *ns = NULL;
2157    size_t             ns_len = 0;
2158    zend_long            options = 0;
2159    zend_class_entry *ce= sxe_class_entry;
2160    zend_bool       isprefix = 0;
2161
2162    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2163        return;
2164    }
2165
2166    docp = xmlReadMemory(data, data_len, NULL, NULL, options);
2167
2168    if (!docp) {
2169        RETURN_FALSE;
2170    }
2171
2172    if (!ce) {
2173        ce = sxe_class_entry;
2174    }
2175    sxe = php_sxe_object_new(ce TSRMLS_CC);
2176    sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2177    sxe->iter.isprefix = isprefix;
2178    php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2179    php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2180
2181    ZVAL_OBJ(return_value, &sxe->zo);
2182}
2183/* }}} */
2184
2185/* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2186   SimpleXMLElement constructor */
2187SXE_METHOD(__construct)
2188{
2189    php_sxe_object *sxe = Z_SXEOBJ_P(getThis());
2190    char           *data, *ns = NULL;
2191    size_t             data_len, ns_len = 0;
2192    xmlDocPtr       docp;
2193    zend_long            options = 0;
2194    zend_bool       is_url = 0, isprefix = 0;
2195    zend_error_handling error_handling;
2196
2197    zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2198    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2199        zend_restore_error_handling(&error_handling TSRMLS_CC);
2200        return;
2201    }
2202
2203    zend_restore_error_handling(&error_handling TSRMLS_CC);
2204
2205    docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
2206
2207    if (!docp) {
2208        ((php_libxml_node_object *)sxe)->document = NULL;
2209        zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
2210        return;
2211    }
2212
2213    sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2214    sxe->iter.isprefix = isprefix;
2215    php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2216    php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2217}
2218/* }}} */
2219
2220zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2221    php_sxe_iterator_dtor,
2222    php_sxe_iterator_valid,
2223    php_sxe_iterator_current_data,
2224    php_sxe_iterator_current_key,
2225    php_sxe_iterator_move_forward,
2226    php_sxe_iterator_rewind,
2227};
2228/* }}} */
2229
2230static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
2231{
2232    xmlChar *prefix  = sxe->iter.nsprefix;
2233    int isprefix  = sxe->iter.isprefix;
2234    int test_elem = sxe->iter.type == SXE_ITER_ELEMENT  && sxe->iter.name;
2235    int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
2236
2237    while (node) {
2238        SKIP_TEXT(node);
2239        if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
2240            if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2241                break;
2242            }
2243        } else if (node->type == XML_ATTRIBUTE_NODE) {
2244            if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2245                break;
2246            }
2247        }
2248next_iter:
2249        node = node->next;
2250    }
2251
2252    if (node && use_data) {
2253        _node_as_zval(sxe, node, &sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
2254    }
2255
2256    return node;
2257}
2258/* }}} */
2259
2260static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
2261{
2262    xmlNodePtr node;
2263
2264    if (!Z_ISUNDEF(sxe->iter.data)) {
2265        zval_ptr_dtor(&sxe->iter.data);
2266        ZVAL_UNDEF(&sxe->iter.data);
2267    }
2268
2269    GET_NODE(sxe, node)
2270
2271    if (node) {
2272        switch (sxe->iter.type) {
2273            case SXE_ITER_ELEMENT:
2274            case SXE_ITER_CHILD:
2275            case SXE_ITER_NONE:
2276                node = node->children;
2277                break;
2278            case SXE_ITER_ATTRLIST:
2279                node = (xmlNodePtr) node->properties;
2280        }
2281        return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
2282    }
2283    return NULL;
2284}
2285/* }}} */
2286
2287zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
2288{
2289    php_sxe_iterator *iterator;
2290
2291    if (by_ref) {
2292        zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2293    }
2294    iterator = emalloc(sizeof(php_sxe_iterator));
2295    zend_iterator_init(&iterator->intern TSRMLS_CC);
2296
2297    ZVAL_COPY(&iterator->intern.data, object);
2298    iterator->intern.funcs = &php_sxe_iterator_funcs;
2299    iterator->sxe = Z_SXEOBJ_P(object);
2300
2301    return (zend_object_iterator*)iterator;
2302}
2303/* }}} */
2304
2305static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2306{
2307    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2308
2309    /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2310    if (!Z_ISUNDEF(iterator->intern.data)) {
2311        zval_ptr_dtor(&iterator->intern.data);
2312    }
2313}
2314/* }}} */
2315
2316static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2317{
2318    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2319
2320    return Z_ISUNDEF(iterator->sxe->iter.data) ? FAILURE : SUCCESS;
2321}
2322/* }}} */
2323
2324static zval *php_sxe_iterator_current_data(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2325{
2326    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2327
2328    return &iterator->sxe->iter.data;
2329}
2330/* }}} */
2331
2332static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
2333{
2334    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2335    zval *curobj = &iterator->sxe->iter.data;
2336    php_sxe_object *intern = Z_SXEOBJ_P(curobj);
2337
2338    xmlNodePtr curnode = NULL;
2339    if (intern != NULL && intern->node != NULL) {
2340        curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2341    }
2342
2343    if (curnode) {
2344        ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name));
2345    } else {
2346        ZVAL_NULL(key);
2347    }
2348}
2349/* }}} */
2350
2351PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
2352{
2353    xmlNodePtr      node = NULL;
2354    php_sxe_object  *intern;
2355
2356    if (!Z_ISUNDEF(sxe->iter.data)) {
2357        intern = Z_SXEOBJ_P(&sxe->iter.data);
2358        GET_NODE(intern, node)
2359        zval_ptr_dtor(&sxe->iter.data);
2360        ZVAL_UNDEF(&sxe->iter.data);
2361    }
2362
2363    if (node) {
2364        php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
2365    }
2366}
2367/* }}} */
2368
2369static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2370{
2371    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2372    php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
2373}
2374/* }}} */
2375
2376static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2377{
2378    php_sxe_object  *sxe;
2379
2380    php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2381    sxe = iterator->sxe;
2382
2383    php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
2384}
2385/* }}} */
2386
2387void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
2388{
2389    php_sxe_object *sxe;
2390    xmlNodePtr node;
2391
2392    sxe = Z_SXEOBJ_P(object);
2393    GET_NODE(sxe, node);
2394    return php_sxe_get_first_node(sxe, node TSRMLS_CC);
2395}
2396/* }}} */
2397
2398/* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2399   Get a simplexml_element object from dom to allow for processing */
2400PHP_FUNCTION(simplexml_import_dom)
2401{
2402    php_sxe_object *sxe;
2403    zval *node;
2404    php_libxml_node_object *object;
2405    xmlNodePtr      nodep = NULL;
2406    zend_class_entry *ce = sxe_class_entry;
2407
2408    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
2409        return;
2410    }
2411
2412    object = Z_LIBXML_NODE_P(node);
2413
2414    nodep = php_libxml_import_node(node TSRMLS_CC);
2415
2416    if (nodep) {
2417        if (nodep->doc == NULL) {
2418            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
2419            RETURN_NULL();
2420        }
2421        if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2422            nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2423        }
2424    }
2425
2426    if (nodep && nodep->type == XML_ELEMENT_NODE) {
2427        if (!ce) {
2428            ce = sxe_class_entry;
2429        }
2430        sxe = php_sxe_object_new(ce TSRMLS_CC);
2431        sxe->document = object->document;
2432        php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
2433        php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
2434
2435        ZVAL_OBJ(return_value, &sxe->zo);
2436    } else {
2437        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
2438        RETVAL_NULL();
2439    }
2440}
2441/* }}} */
2442
2443/* {{{ arginfo */
2444ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2445    ZEND_ARG_INFO(0, filename)
2446    ZEND_ARG_INFO(0, class_name)
2447    ZEND_ARG_INFO(0, options)
2448    ZEND_ARG_INFO(0, ns)
2449    ZEND_ARG_INFO(0, is_prefix)
2450ZEND_END_ARG_INFO()
2451
2452ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2453    ZEND_ARG_INFO(0, data)
2454    ZEND_ARG_INFO(0, class_name)
2455    ZEND_ARG_INFO(0, options)
2456    ZEND_ARG_INFO(0, ns)
2457    ZEND_ARG_INFO(0, is_prefix)
2458ZEND_END_ARG_INFO()
2459
2460ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2461    ZEND_ARG_INFO(0, node)
2462    ZEND_ARG_INFO(0, class_name)
2463ZEND_END_ARG_INFO()
2464
2465ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2466    ZEND_ARG_INFO(0, path)
2467ZEND_END_ARG_INFO()
2468
2469ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2470    ZEND_ARG_INFO(0, prefix)
2471    ZEND_ARG_INFO(0, ns)
2472ZEND_END_ARG_INFO()
2473
2474ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2475    ZEND_ARG_INFO(0, filename)
2476ZEND_END_ARG_INFO()
2477
2478ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2479    ZEND_ARG_INFO(0, recursve)
2480ZEND_END_ARG_INFO()
2481
2482ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getdocnamespaces, 0, 0, 0)
2483    ZEND_ARG_INFO(0, recursve)
2484    ZEND_ARG_INFO(0, from_root)
2485ZEND_END_ARG_INFO()
2486
2487ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2488    ZEND_ARG_INFO(0, ns)
2489    ZEND_ARG_INFO(0, is_prefix)
2490ZEND_END_ARG_INFO()
2491
2492ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2493    ZEND_ARG_INFO(0, data)
2494    ZEND_ARG_INFO(0, options)
2495    ZEND_ARG_INFO(0, data_is_url)
2496    ZEND_ARG_INFO(0, ns)
2497    ZEND_ARG_INFO(0, is_prefix)
2498ZEND_END_ARG_INFO()
2499
2500ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2501ZEND_END_ARG_INFO()
2502
2503ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2504    ZEND_ARG_INFO(0, name)
2505    ZEND_ARG_INFO(0, value)
2506    ZEND_ARG_INFO(0, ns)
2507ZEND_END_ARG_INFO()
2508/* }}} */
2509
2510const zend_function_entry simplexml_functions[] = { /* {{{ */
2511    PHP_FE(simplexml_load_file,     arginfo_simplexml_load_file)
2512    PHP_FE(simplexml_load_string,   arginfo_simplexml_load_string)
2513    PHP_FE(simplexml_import_dom,    arginfo_simplexml_import_dom)
2514    PHP_FE_END
2515};
2516/* }}} */
2517
2518static const zend_module_dep simplexml_deps[] = { /* {{{ */
2519    ZEND_MOD_REQUIRED("libxml")
2520    ZEND_MOD_REQUIRED("spl")
2521    ZEND_MOD_END
2522};
2523/* }}} */
2524
2525zend_module_entry simplexml_module_entry = { /* {{{ */
2526    STANDARD_MODULE_HEADER_EX, NULL,
2527    simplexml_deps,
2528    "SimpleXML",
2529    simplexml_functions,
2530    PHP_MINIT(simplexml),
2531    PHP_MSHUTDOWN(simplexml),
2532    NULL,
2533    NULL,
2534    PHP_MINFO(simplexml),
2535    "0.1",
2536    STANDARD_MODULE_PROPERTIES
2537};
2538/* }}} */
2539
2540#ifdef COMPILE_DL_SIMPLEXML
2541ZEND_GET_MODULE(simplexml)
2542#endif
2543
2544/* the method table */
2545/* each method can have its own parameters and visibility */
2546static const zend_function_entry sxe_functions[] = { /* {{{ */
2547    SXE_ME(__construct,            arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2548    SXE_ME(asXML,                  arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2549    SXE_MALIAS(saveXML, asXML,     arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2550    SXE_ME(xpath,                  arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2551    SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2552    SXE_ME(attributes,             arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2553    SXE_ME(children,               arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2554    SXE_ME(getNamespaces,          arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2555    SXE_ME(getDocNamespaces,       arginfo_simplexmlelement_getdocnamespaces, ZEND_ACC_PUBLIC)
2556    SXE_ME(getName,                arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2557    SXE_ME(addChild,               arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2558    SXE_ME(addAttribute,           arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2559    SXE_ME(__toString,             arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2560    SXE_ME(count,                  arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2561    PHP_FE_END
2562};
2563/* }}} */
2564
2565/* {{{ PHP_MINIT_FUNCTION(simplexml)
2566 */
2567PHP_MINIT_FUNCTION(simplexml)
2568{
2569    zend_class_entry sxe;
2570
2571    INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2572    sxe.create_object = sxe_object_new;
2573    sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
2574    sxe_class_entry->get_iterator = php_sxe_get_iterator;
2575    sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2576    zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2577    sxe_object_handlers.offset = XtOffsetOf(php_sxe_object, zo);
2578    sxe_object_handlers.dtor_obj = sxe_object_dtor;
2579    sxe_object_handlers.free_obj = sxe_object_free_storage;
2580    sxe_object_handlers.clone_obj = sxe_object_clone;
2581    sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2582    sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2583    sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
2584    sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2585    sxe_class_entry->serialize = zend_class_serialize_deny;
2586    sxe_class_entry->unserialize = zend_class_unserialize_deny;
2587
2588    php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2589
2590    PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2591
2592    return SUCCESS;
2593}
2594/* }}} */
2595
2596/* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2597 */
2598PHP_MSHUTDOWN_FUNCTION(simplexml)
2599{
2600    sxe_class_entry = NULL;
2601    return SUCCESS;
2602}
2603/* }}} */
2604
2605/* {{{ PHP_MINFO_FUNCTION(simplexml)
2606 */
2607PHP_MINFO_FUNCTION(simplexml)
2608{
2609    php_info_print_table_start();
2610    php_info_print_table_header(2, "Simplexml support", "enabled");
2611    php_info_print_table_row(2, "Revision", "$Id: db4944ff5ad867c6ddcfd17e31f3e94e85938fe6 $");
2612    php_info_print_table_row(2, "Schema support",
2613#ifdef LIBXML_SCHEMAS_ENABLED
2614        "enabled");
2615#else
2616        "not available");
2617#endif
2618    php_info_print_table_end();
2619}
2620/* }}} */
2621
2622#endif
2623
2624/**
2625 * Local Variables:
2626 * c-basic-offset: 4
2627 * tab-width: 4
2628 * indent-tabs-mode: t
2629 * End:
2630 * vim600: fdm=marker
2631 * vim: noet sw=4 ts=4
2632 */
2633