Back to index

php5  5.3.10
simplexml.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Sterling Hughes <sterling@php.net>                          |
00016   |          Marcus Boerger <helly@php.net>                              |
00017   |          Rob Richards <rrichards@php.net>                            |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: simplexml.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include "php.h"
00028 #if HAVE_LIBXML && HAVE_SIMPLEXML
00029 
00030 #include "php_ini.h"
00031 #include "ext/standard/info.h"
00032 #include "ext/standard/php_string.h"
00033 #include "php_simplexml.h"
00034 #include "php_simplexml_exports.h"
00035 #include "zend_exceptions.h"
00036 #include "zend_interfaces.h"
00037 #include "sxe.h"
00038 
00039 #define SXE_ELEMENT_BY_NAME 0
00040 
00041 zend_class_entry *sxe_class_entry = NULL;
00042 
00043 PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */
00044 {
00045        return sxe_class_entry;
00046 }
00047 /* }}} */
00048 
00049 #define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags)
00050 #define SXE_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(simplexml_element, func, alias, arg_info, flags)
00051 
00052 #define SXE_METHOD(func) PHP_METHOD(simplexml_element, func)
00053 
00054 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC);
00055 static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC);
00056 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC);
00057 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC);
00058 static zval *sxe_get_value(zval *z TSRMLS_DC);
00059 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC);
00060 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC);
00061 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
00062 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
00063 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC);
00064 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC);
00065 
00066 /* {{{ _node_as_zval()
00067  */
00068 static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix TSRMLS_DC)
00069 {
00070        php_sxe_object *subnode;
00071 
00072        subnode = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
00073        subnode->document = sxe->document;
00074        subnode->document->refcount++;
00075        subnode->iter.type = itertype;
00076        if (name) {
00077               subnode->iter.name = xmlStrdup((xmlChar *)name);
00078        }
00079        if (nsprefix && *nsprefix) {
00080               subnode->iter.nsprefix = xmlStrdup(nsprefix);
00081               subnode->iter.isprefix = isprefix;
00082        }
00083 
00084        php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
00085 
00086        value->type = IS_OBJECT;
00087        value->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
00088 }
00089 /* }}} */
00090 
00091 #define APPEND_PREV_ELEMENT(__c, __v) \
00092        if ((__c) == 1) { \
00093               array_init(return_value); \
00094               add_next_index_zval(return_value, __v); \
00095        }
00096 
00097 #define APPEND_CUR_ELEMENT(__c, __v) \
00098        if (++(__c) > 1) { \
00099               add_next_index_zval(return_value, __v); \
00100        }
00101 
00102 #define GET_NODE(__s, __n) { \
00103        if ((__s)->node && (__s)->node->node) { \
00104               __n = (__s)->node->node; \
00105        } else { \
00106               __n = NULL; \
00107               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node no longer exists"); \
00108        } \
00109 }
00110 
00111 static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node TSRMLS_DC) /* {{{ */
00112 {
00113        php_sxe_object *intern;
00114        xmlNodePtr retnode = NULL;
00115 
00116        if (sxe && sxe->iter.type != SXE_ITER_NONE) {
00117               php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
00118               if (sxe->iter.data) {
00119                      intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
00120                      GET_NODE(intern, retnode)
00121               }
00122               return retnode;
00123        } else {
00124               return node;
00125        }
00126 }
00127 /* }}} */
00128 
00129 static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
00130 {
00131        if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
00132               return 1;
00133        }
00134 
00135        if (node->ns && !xmlStrcmp(prefix ? node->ns->prefix : node->ns->href, name)) {
00136               return 1;
00137        }
00138 
00139        return 0;
00140 }
00141 /* }}} */
00142 
00143 static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, long offset, xmlNodePtr node, long *cnt) /* {{{ */
00144 {
00145        long nodendx = 0;
00146 
00147        if (sxe->iter.type == SXE_ITER_NONE) {
00148               if (offset == 0) {
00149                      if (cnt) {
00150                             *cnt = 0;
00151                      }
00152                      return node;
00153               } else {
00154                      return NULL;
00155               }
00156        }
00157        while (node && nodendx <= offset) {
00158               SKIP_TEXT(node)
00159               if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00160                      if (sxe->iter.type == SXE_ITER_CHILD || (
00161                             sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) {
00162                             if (nodendx == offset) {
00163                                    break;
00164                             }
00165                             nodendx++;
00166                      }
00167               }
00168 next_iter:
00169               node = node->next;
00170        }
00171 
00172        if (cnt) {
00173               *cnt = nodendx;
00174        }
00175 
00176        return node;
00177 }
00178 /* }}} */
00179 
00180 static xmlNodePtr sxe_find_element_by_name(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name TSRMLS_DC) /* {{{ */
00181 {
00182        while (node) {
00183               SKIP_TEXT(node)
00184               if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00185                      if (!xmlStrcmp(node->name, name)) {
00186                             return node;
00187                      }
00188               }
00189 next_iter:
00190               node = node->next;
00191        }
00192        return NULL;
00193 } /* }}} */
00194 
00195 static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, char **name, SXE_ITER *type TSRMLS_DC) /* {{{ */
00196 {
00197        int         orgtype;
00198        xmlNodePtr  orgnode = node;
00199        xmlNodePtr  retnode = NULL;
00200 
00201        if (sxe->iter.type != SXE_ITER_ATTRLIST)
00202        {
00203               orgtype = sxe->iter.type;
00204               if (sxe->iter.type == SXE_ITER_NONE) {
00205                      sxe->iter.type = SXE_ITER_CHILD;
00206               }
00207               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00208               sxe->iter.type = orgtype;
00209        }
00210 
00211        if (sxe->iter.type == SXE_ITER_ELEMENT) {
00212               orgnode = sxe_find_element_by_name(sxe, node, sxe->iter.name TSRMLS_CC);
00213               if (!orgnode) {
00214                      return NULL;
00215               }
00216               node = orgnode->children;
00217        }
00218 
00219        while (node) {
00220               SKIP_TEXT(node)
00221               if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00222                      if (!xmlStrcmp(node->name, (xmlChar *)*name)) {
00223                             if (1||retnode)
00224                             {
00225                                    *type = SXE_ITER_ELEMENT;
00226                                    return orgnode;
00227                             }
00228                             retnode = node;
00229                      }
00230               }
00231 next_iter:
00232               node = node->next;
00233        }
00234 
00235        if (retnode)
00236        {
00237               *type = SXE_ITER_NONE;
00238               *name = NULL;
00239               return retnode;
00240        }
00241 
00242        return NULL;
00243 }
00244 /* }}} */
00245 
00246 /* {{{ sxe_prop_dim_read()
00247  */
00248 static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type TSRMLS_DC)
00249 {
00250        zval           *return_value;
00251        php_sxe_object *sxe;
00252        char           *name;
00253        xmlNodePtr      node;
00254        xmlAttrPtr      attr = NULL;
00255        zval            tmp_zv;
00256        int             nodendx = 0;
00257        int             test = 0;
00258 
00259        sxe = php_sxe_fetch_object(object TSRMLS_CC);
00260 
00261        if (!member || Z_TYPE_P(member) == IS_LONG) {
00262               if (sxe->iter.type != SXE_ITER_ATTRLIST) {
00263                      attribs = 0;
00264                      elements = 1;
00265               } else if (!member) {
00266                      /* This happens when the user did: $sxe[]->foo = $value */
00267                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
00268                      return NULL;
00269               }
00270               name = NULL;
00271        } else {
00272               if (Z_TYPE_P(member) != IS_STRING) {
00273                      tmp_zv = *member;
00274                      zval_copy_ctor(&tmp_zv);
00275                      member = &tmp_zv;
00276                      convert_to_string(member);
00277               }
00278               name = Z_STRVAL_P(member);
00279        }
00280 
00281        GET_NODE(sxe, node);
00282 
00283        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
00284               attribs = 1;
00285               elements = 0;
00286               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00287               attr = (xmlAttrPtr)node;
00288               test = sxe->iter.name != NULL;
00289        } else if (sxe->iter.type != SXE_ITER_CHILD) {
00290               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00291               attr = node ? node->properties : NULL;
00292               test = 0;
00293               if (!member && node && node->parent &&
00294                   node->parent->type == XML_DOCUMENT_NODE) {
00295                      /* This happens when the user did: $sxe[]->foo = $value */
00296                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
00297                      return NULL;
00298               }
00299        }
00300 
00301        MAKE_STD_ZVAL(return_value);
00302        ZVAL_NULL(return_value);
00303 
00304        if (node) {
00305               if (attribs) {
00306                      if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) {
00307                             if (Z_TYPE_P(member) == IS_LONG) {
00308                                    while (attr && nodendx <= Z_LVAL_P(member)) {
00309                                           if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00310                                                  if (nodendx == Z_LVAL_P(member)) {
00311                                                         _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00312                                                         break;
00313                                                  }
00314                                                  nodendx++;
00315                                           }
00316                                           attr = attr->next;
00317                                    }
00318                             } else {
00319                                    while (attr) {
00320                                           if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00321                                                  _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00322                                                  break;
00323                                           }
00324                                           attr = attr->next;
00325                                    }
00326                             }
00327                      }
00328               }
00329 
00330               if (elements) {
00331                      if (!sxe->node) {
00332                             php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC);
00333                      }
00334                      if (!member || Z_TYPE_P(member) == IS_LONG) {
00335                             long cnt = 0;
00336                             xmlNodePtr mynode = node;
00337 
00338                             if (sxe->iter.type == SXE_ITER_CHILD) {
00339                                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00340                             }
00341                             if (sxe->iter.type == SXE_ITER_NONE) {
00342                                    if (member && Z_LVAL_P(member) > 0) {
00343                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
00344                                    }
00345                             } else if (member) {
00346                                    node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
00347                             } else {
00348                                    node = NULL;
00349                             }
00350                             if (node) {
00351                                    _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00352                             } else if (type == BP_VAR_W || type == BP_VAR_RW) {
00353                                    if (member && cnt < Z_LVAL_P(member)) {
00354                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
00355                                    }
00356                                    node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
00357                                    _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00358                             }
00359                      } else {
00360 #if SXE_ELEMENT_BY_NAME
00361                             int newtype;
00362 
00363                             GET_NODE(sxe, node);
00364                             node = sxe_get_element_by_name(sxe, node, &name, &newtype TSRMLS_CC);
00365                             if (node) {
00366                                    _node_as_zval(sxe, node, return_value, newtype, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00367                             }
00368 #else
00369                             _node_as_zval(sxe, node, return_value, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00370 #endif
00371                      }
00372               }
00373        }
00374 
00375        Z_SET_REFCOUNT_P(return_value, 0);
00376        Z_UNSET_ISREF_P(return_value);
00377 
00378        if (member == &tmp_zv) {
00379               zval_dtor(&tmp_zv);
00380        }
00381        if (Z_TYPE_P(return_value) == IS_NULL) {
00382               FREE_ZVAL(return_value);
00383               return_value = &EG(uninitialized_zval);
00384        }
00385 
00386        return return_value;
00387 }
00388 /* }}} */
00389 
00390 /* {{{ sxe_property_read()
00391  */
00392 static zval * sxe_property_read(zval *object, zval *member, int type TSRMLS_DC)
00393 {
00394        return sxe_prop_dim_read(object, member, 1, 0, type TSRMLS_CC);
00395 }
00396 /* }}} */
00397 
00398 /* {{{ sxe_dimension_read()
00399  */
00400 static zval * sxe_dimension_read(zval *object, zval *offset, int type TSRMLS_DC)
00401 {
00402        return sxe_prop_dim_read(object, offset, 0, 1, type TSRMLS_CC);
00403 }
00404 /* }}} */
00405 
00406 /* {{{ change_node_zval()
00407  */
00408 static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC)
00409 {
00410        zval value_copy;
00411        xmlChar *buffer;
00412        int buffer_len;
00413 
00414        if (!value)
00415        {
00416               xmlNodeSetContentLen(node, (xmlChar *)"", 0);
00417               return;
00418        }
00419        switch (Z_TYPE_P(value)) {
00420               case IS_LONG:
00421               case IS_BOOL:
00422               case IS_DOUBLE:
00423               case IS_NULL:
00424                      if (Z_REFCOUNT_P(value) > 1) {
00425                             value_copy = *value;
00426                             zval_copy_ctor(&value_copy);
00427                             value = &value_copy;
00428                      }
00429                      convert_to_string(value);
00430                      /* break missing intentionally */
00431               case IS_STRING:
00432                      buffer = xmlEncodeEntitiesReentrant(node->doc, (xmlChar *)Z_STRVAL_P(value));
00433                      buffer_len = xmlStrlen(buffer);
00434                      /* check for NULL buffer in case of memory error in xmlEncodeEntitiesReentrant */
00435                      if (buffer) {
00436                             xmlNodeSetContentLen(node, buffer, buffer_len);
00437                             xmlFree(buffer);
00438                      }
00439                      if (value == &value_copy) {
00440                             zval_dtor(value);
00441                      }
00442                      break;
00443               default:
00444                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not possible to assign complex types to nodes");
00445                      break;
00446        }
00447 }
00448 /* }}} */
00449 
00450 /* {{{ sxe_property_write()
00451  */
00452 static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode TSRMLS_DC)
00453 {
00454        php_sxe_object *sxe;
00455        xmlNodePtr      node;
00456        xmlNodePtr      newnode = NULL;
00457        xmlNodePtr      mynode;
00458        xmlNodePtr           tempnode;
00459        xmlAttrPtr      attr = NULL;
00460        int             counter = 0;
00461        int             is_attr = 0;
00462        int                         nodendx = 0;
00463        int             test = 0;
00464        int                         new_value = 0;
00465        long            cnt = 0;
00466        int                         retval = SUCCESS;
00467        zval            tmp_zv, trim_zv, value_copy;
00468 
00469        sxe = php_sxe_fetch_object(object TSRMLS_CC);
00470 
00471        if (!member || Z_TYPE_P(member) == IS_LONG) {
00472               if (sxe->iter.type != SXE_ITER_ATTRLIST) {
00473                      attribs = 0;
00474                      elements = 1;
00475               } else if (!member) {
00476                      /* This happens when the user did: $sxe[] = $value
00477                       * and could also be E_PARSE, but we use this only during parsing
00478                       * and this is during runtime.
00479                       */
00480                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
00481                      return FAILURE;
00482               }
00483        } else {
00484               if (Z_TYPE_P(member) != IS_STRING) {
00485                      trim_zv = *member;
00486                      zval_copy_ctor(&trim_zv);
00487                      convert_to_string(&trim_zv);
00488                      php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC);
00489                      zval_dtor(&trim_zv);
00490                      member = &tmp_zv;
00491               }
00492 
00493               if (!Z_STRLEN_P(member)) {
00494                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element");
00495                      if (member == &tmp_zv) {
00496                             zval_dtor(&tmp_zv);
00497                      }
00498                      return FAILURE;
00499               }
00500        }
00501 
00502        GET_NODE(sxe, node);
00503 
00504        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
00505               attribs = 1;
00506               elements = 0;
00507               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00508               attr = (xmlAttrPtr)node;
00509               test = sxe->iter.name != NULL;
00510        } else if (sxe->iter.type != SXE_ITER_CHILD) {
00511               mynode = node;
00512               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00513               attr = node ? node->properties : NULL;
00514               test = 0;
00515               if (!member && node && node->parent &&
00516                   node->parent->type == XML_DOCUMENT_NODE) {
00517                      /* This happens when the user did: $sxe[] = $value
00518                       * and could also be E_PARSE, but we use this only during parsing
00519                       * and this is during runtime.
00520                       */
00521                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
00522                      return FAILURE;
00523               }
00524               if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) {
00525                      node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL);
00526                      attr = node->properties;
00527               }
00528        }
00529 
00530        mynode = node;
00531 
00532        if (value) {
00533               switch (Z_TYPE_P(value)) {
00534                      case IS_LONG:
00535                      case IS_BOOL:
00536                      case IS_DOUBLE:
00537                      case IS_NULL:
00538                             if (Z_REFCOUNT_P(value) > 1) {
00539                                    value_copy = *value;
00540                                    zval_copy_ctor(&value_copy);
00541                                    value = &value_copy;
00542                             }
00543                             convert_to_string(value);
00544                             break;
00545                      case IS_STRING:
00546                             break;
00547                      case IS_OBJECT:
00548                             if (Z_OBJCE_P(value) == sxe_class_entry) {
00549                                    value = sxe_get_value(value TSRMLS_CC);
00550                                    INIT_PZVAL(value);
00551                                    new_value = 1;
00552                                    break;
00553                             }
00554                             /* break is missing intentionally */
00555                      default:
00556                             if (member == &tmp_zv) {
00557                                    zval_dtor(&tmp_zv);
00558                             }
00559                             zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties");
00560                             return FAILURE;
00561               }
00562        }
00563 
00564        if (node) {
00565               if (attribs) {
00566                      if (Z_TYPE_P(member) == IS_LONG) {
00567                             while (attr && nodendx <= Z_LVAL_P(member)) {
00568                                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00569                                           if (nodendx == Z_LVAL_P(member)) {
00570                                                  is_attr = 1;
00571                                                  ++counter;
00572                                                  break;
00573                                           }
00574                                           nodendx++;
00575                                    }
00576                                    attr = attr->next;
00577                             }
00578                      } else {
00579                             while (attr) {
00580                                    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)) {
00581                                           is_attr = 1;
00582                                           ++counter;
00583                                           break;
00584                                    }
00585                                    attr = attr->next;
00586                             }
00587                      }
00588 
00589               }
00590 
00591               if (elements) {
00592                      if (!member || Z_TYPE_P(member) == IS_LONG) {
00593                             if (node->type == XML_ATTRIBUTE_NODE) {
00594                                    php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create duplicate attribute");
00595                                    return FAILURE;
00596                             }
00597 
00598                             if (sxe->iter.type == SXE_ITER_NONE) {
00599                                    newnode = node;
00600                                    ++counter;
00601                                    if (member && Z_LVAL_P(member) > 0) {
00602                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
00603                                           retval = FAILURE;
00604                                    }
00605                             } else if (member) {
00606                                    newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
00607                                    if (newnode) {
00608                                           ++counter;
00609                                    }
00610                             }
00611                      } else {
00612                             node = node->children;
00613                             while (node) {
00614                                    SKIP_TEXT(node);
00615 
00616                                    if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
00617                                           newnode = node;
00618                                           ++counter;
00619                                    }
00620 
00621 next_iter:
00622                                    node = node->next;
00623                             }
00624                      }
00625               }
00626 
00627               if (counter == 1) {
00628                      if (is_attr) {
00629                             newnode = (xmlNodePtr) attr;
00630                      }
00631                      if (value) {
00632                             while ((tempnode = (xmlNodePtr) newnode->children)) {
00633                                    xmlUnlinkNode(tempnode);
00634                                    php_libxml_node_free_resource((xmlNodePtr) tempnode TSRMLS_CC);
00635                             }
00636                             change_node_zval(newnode, value TSRMLS_CC);
00637                      }
00638               } else if (counter > 1) {
00639                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)");
00640                      retval = FAILURE;
00641               } else if (elements) {
00642                      if (!node) {
00643                             if (!member || Z_TYPE_P(member) == IS_LONG) {
00644                                    newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
00645                             } else {
00646                                    newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
00647                             }
00648                      } else if (!member || Z_TYPE_P(member) == IS_LONG) {
00649                             if (member && cnt < Z_LVAL_P(member)) {
00650                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
00651                                    retval = FAILURE;
00652                             }
00653                             newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
00654                      }
00655               } else if (attribs) {
00656                      if (Z_TYPE_P(member) == IS_LONG) {
00657                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change attribute number %ld when only %d attributes exist", Z_LVAL_P(member), nodendx);
00658                             retval = FAILURE;
00659                      } else {
00660                             newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
00661                      }
00662               }
00663        }
00664 
00665        if (member == &tmp_zv) {
00666               zval_dtor(&tmp_zv);
00667        }
00668        if (pnewnode) {
00669               *pnewnode = newnode;
00670        }
00671        if (value && value == &value_copy) {
00672               zval_dtor(value);
00673        }
00674        if (new_value) {
00675               zval_ptr_dtor(&value);
00676        }
00677        return retval;
00678 }
00679 /* }}} */
00680 
00681 /* {{{ sxe_property_write()
00682  */
00683 static void sxe_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
00684 {
00685        sxe_prop_dim_write(object, member, value, 1, 0, NULL TSRMLS_CC);
00686 }
00687 /* }}} */
00688 
00689 /* {{{ sxe_dimension_write()
00690  */
00691 static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_DC)
00692 {
00693        sxe_prop_dim_write(object, offset, value, 0, 1, NULL TSRMLS_CC);
00694 }
00695 /* }}} */
00696 
00697 static zval** sxe_property_get_adr(zval *object, zval *member TSRMLS_DC) /* {{{ */
00698 {
00699        php_sxe_object *sxe;
00700        xmlNodePtr      node;
00701        zval           *return_value;
00702        char           *name;
00703        SXE_ITER        type;
00704 
00705        sxe = php_sxe_fetch_object(object TSRMLS_CC);
00706 
00707        GET_NODE(sxe, node);
00708        convert_to_string(member);
00709        name = Z_STRVAL_P(member);
00710        node = sxe_get_element_by_name(sxe, node, &name, &type TSRMLS_CC);
00711        if (node) {
00712               return NULL;
00713        }
00714        if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node TSRMLS_CC) != SUCCESS) {
00715               return NULL;
00716        }
00717        type = SXE_ITER_NONE;
00718        name = NULL;
00719 
00720        MAKE_STD_ZVAL(return_value);
00721        _node_as_zval(sxe, node, return_value, type, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
00722 
00723        sxe = php_sxe_fetch_object(return_value TSRMLS_CC);
00724        if (sxe->tmp) {
00725               zval_ptr_dtor(&sxe->tmp);
00726        }
00727        sxe->tmp = return_value;
00728        Z_SET_ISREF_P(return_value);
00729 
00730        return &sxe->tmp;
00731 }
00732 /* }}} */
00733 
00734 /* {{{ sxe_prop_dim_exists()
00735  */
00736 static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs TSRMLS_DC)
00737 {
00738        php_sxe_object *sxe;
00739        xmlNodePtr      node;
00740        xmlAttrPtr      attr = NULL;
00741        int                         exists = 0;
00742        int             test = 0;
00743        zval            tmp_zv;
00744 
00745        if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
00746               tmp_zv = *member;
00747               zval_copy_ctor(&tmp_zv);
00748               member = &tmp_zv;
00749               convert_to_string(member);
00750        }
00751 
00752        sxe = php_sxe_fetch_object(object TSRMLS_CC);
00753 
00754        GET_NODE(sxe, node);
00755 
00756        if (Z_TYPE_P(member) == IS_LONG) {
00757               if (sxe->iter.type != SXE_ITER_ATTRLIST) {
00758                      attribs = 0;
00759                      elements = 1;
00760                      if (sxe->iter.type == SXE_ITER_CHILD) {
00761                             node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00762                      }
00763               }
00764        }
00765 
00766        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
00767               attribs = 1;
00768               elements = 0;
00769               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00770               attr = (xmlAttrPtr)node;
00771               test = sxe->iter.name != NULL;
00772        } else if (sxe->iter.type != SXE_ITER_CHILD) {
00773               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00774               attr = node ? node->properties : NULL;
00775               test = 0;
00776        }
00777 
00778        if (node) {
00779               if (attribs) {
00780                      if (Z_TYPE_P(member) == IS_LONG) {
00781                             int    nodendx = 0;
00782 
00783                             while (attr && nodendx <= Z_LVAL_P(member)) {
00784                                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00785                                           if (nodendx == Z_LVAL_P(member)) {
00786                                                  exists = 1;
00787                                                  break;
00788                                           }
00789                                           nodendx++;
00790                                    }
00791                                    attr = attr->next;
00792                             }
00793                      } else {
00794                             while (attr) {
00795                                    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)) {
00796                                           exists = 1;
00797                                           break;
00798                                    }
00799 
00800                                    attr = attr->next;
00801                             }
00802                      }
00803                      if (exists && check_empty == 1 &&
00804                             (!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, "0")) ) {
00805                             /* Attribute with no content in it's text node */
00806                             exists = 0;
00807                      }
00808               }
00809 
00810               if (elements) {
00811                      if (Z_TYPE_P(member) == IS_LONG) {
00812                             if (sxe->iter.type == SXE_ITER_CHILD) {
00813                                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00814                             }
00815                             node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
00816                      }
00817                      else {
00818                             node = node->children;
00819                             while (node) {
00820                                    xmlNodePtr nnext;
00821                                    nnext = node->next;
00822                                    if ((node->type == XML_ELEMENT_NODE) && !xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
00823                                           break;
00824                                    }
00825                                    node = nnext;
00826                             }
00827                      }
00828                      if (node) {
00829                             exists = 1;
00830                                 if (check_empty == 1 &&
00831                                    (!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
00832                                           (!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, "0")))) ) {
00833                                    exists = 0;
00834                             }
00835                      }
00836               }
00837        }
00838 
00839        if (member == &tmp_zv) {
00840               zval_dtor(&tmp_zv);
00841        }
00842 
00843        return exists;
00844 }
00845 /* }}} */
00846 
00847 /* {{{ sxe_property_exists()
00848  */
00849 static int sxe_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
00850 {
00851        return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC);
00852 }
00853 /* }}} */
00854 
00855 /* {{{ sxe_property_exists()
00856  */
00857 static int sxe_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
00858 {
00859        return sxe_prop_dim_exists(object, member, check_empty, 0, 1 TSRMLS_CC);
00860 }
00861 /* }}} */
00862 
00863 /* {{{ sxe_prop_dim_delete()
00864  */
00865 static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs TSRMLS_DC)
00866 {
00867        php_sxe_object *sxe;
00868        xmlNodePtr      node;
00869        xmlNodePtr      nnext;
00870        xmlAttrPtr      attr = NULL;
00871        xmlAttrPtr      anext;
00872        zval            tmp_zv;
00873        int             test = 0;
00874 
00875        if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
00876               tmp_zv = *member;
00877               zval_copy_ctor(&tmp_zv);
00878               member = &tmp_zv;
00879               convert_to_string(member);
00880        }
00881 
00882        sxe = php_sxe_fetch_object(object TSRMLS_CC);
00883 
00884        GET_NODE(sxe, node);
00885 
00886        if (Z_TYPE_P(member) == IS_LONG) {
00887               if (sxe->iter.type != SXE_ITER_ATTRLIST) {
00888                      attribs = 0;
00889                      elements = 1;
00890                      if (sxe->iter.type == SXE_ITER_CHILD) {
00891                             node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00892                      }
00893               }
00894        }
00895 
00896        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
00897               attribs = 1;
00898               elements = 0;
00899               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00900               attr = (xmlAttrPtr)node;
00901               test = sxe->iter.name != NULL;
00902        } else if (sxe->iter.type != SXE_ITER_CHILD) {
00903               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00904               attr = node ? node->properties : NULL;
00905               test = 0;
00906        }
00907 
00908        if (node) {
00909               if (attribs) {
00910                      if (Z_TYPE_P(member) == IS_LONG) {
00911                             int    nodendx = 0;
00912 
00913                             while (attr && nodendx <= Z_LVAL_P(member)) {
00914                                    if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
00915                                           if (nodendx == Z_LVAL_P(member)) {
00916                                                  xmlUnlinkNode((xmlNodePtr) attr);
00917                                                  php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
00918                                                  break;
00919                                           }
00920                                           nodendx++;
00921                                    }
00922                                    attr = attr->next;
00923                             }
00924                      } else {
00925                             while (attr) {
00926                                    anext = attr->next;
00927                                    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)) {
00928                                           xmlUnlinkNode((xmlNodePtr) attr);
00929                                           php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
00930                                           break;
00931                                    }
00932                                    attr = anext;
00933                             }
00934                      }
00935               }
00936 
00937               if (elements) {
00938                      if (Z_TYPE_P(member) == IS_LONG) {
00939                             if (sxe->iter.type == SXE_ITER_CHILD) {
00940                                    node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
00941                             }
00942                             node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
00943                             if (node) {
00944                                    xmlUnlinkNode(node);
00945                                    php_libxml_node_free_resource(node TSRMLS_CC);
00946                             }
00947                      } else {
00948                             node = node->children;
00949                             while (node) {
00950                                    nnext = node->next;
00951 
00952                                    SKIP_TEXT(node);
00953 
00954                                    if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
00955                                           xmlUnlinkNode(node);
00956                                           php_libxml_node_free_resource(node TSRMLS_CC);
00957                                    }
00958 
00959 next_iter:
00960                                    node = nnext;
00961                             }
00962                      }
00963               }
00964        }
00965 
00966        if (member == &tmp_zv) {
00967               zval_dtor(&tmp_zv);
00968        }
00969 }
00970 /* }}} */
00971 
00972 /* {{{ sxe_property_delete()
00973  */
00974 static void sxe_property_delete(zval *object, zval *member TSRMLS_DC)
00975 {
00976        sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC);
00977 }
00978 /* }}} */
00979 
00980 /* {{{ sxe_dimension_unset()
00981  */
00982 static void sxe_dimension_delete(zval *object, zval *offset TSRMLS_DC)
00983 {
00984        sxe_prop_dim_delete(object, offset, 0, 1 TSRMLS_CC);
00985 }
00986 /* }}} */
00987 
00988 static inline char * sxe_xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) /* {{{ */
00989 {
00990        xmlChar *tmp = xmlNodeListGetString(doc, list, inLine);
00991        char    *res;
00992        
00993        if (tmp) {
00994               res = estrdup((char*)tmp);
00995               xmlFree(tmp);
00996        } else {
00997               res = STR_EMPTY_ALLOC();
00998        }
00999 
01000        return res;
01001 }
01002 /* }}} */
01003 
01004 /* {{{ _get_base_node_value()
01005  */
01006 static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval **value, xmlChar *nsprefix, int isprefix TSRMLS_DC)
01007 {
01008        php_sxe_object *subnode;
01009        xmlChar        *contents;
01010 
01011        MAKE_STD_ZVAL(*value);
01012 
01013        if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
01014               contents = xmlNodeListGetString(node->doc, node->children, 1);
01015               if (contents) {
01016                      ZVAL_STRING(*value, (char *)contents, 1);
01017                      xmlFree(contents);
01018               }
01019        } else {
01020               subnode = php_sxe_object_new(sxe_ref->zo.ce TSRMLS_CC);
01021               subnode->document = sxe_ref->document;
01022               subnode->document->refcount++;
01023               if (nsprefix && *nsprefix) {
01024                      subnode->iter.nsprefix = xmlStrdup((xmlChar *)nsprefix);
01025                      subnode->iter.isprefix = isprefix;
01026               }
01027               php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
01028 
01029               (*value)->type = IS_OBJECT;
01030               (*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
01031               /*zval_add_ref(value);*/
01032        }
01033 }
01034 /* }}} */
01035 
01036 static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value TSRMLS_DC) /* {{{ */
01037 {
01038        zval  **data_ptr;
01039        zval  *newptr;
01040        ulong h = zend_hash_func(name, namelen);
01041 
01042        if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) {
01043               if (Z_TYPE_PP(data_ptr) == IS_ARRAY) {
01044                      zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL);
01045               } else {
01046                      MAKE_STD_ZVAL(newptr);
01047                      array_init(newptr);
01048 
01049                      zval_add_ref(data_ptr);
01050                      zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL);
01051                      zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL);
01052 
01053                      zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL);
01054               }
01055        } else {
01056               zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL);
01057        }
01058 }
01059 /* }}} */
01060 
01061 static HashTable * sxe_get_prop_hash(zval *object, int is_debug TSRMLS_DC) /* {{{ */
01062 {
01063        zval            *value;
01064        zval            *zattr;
01065        HashTable       *rv;
01066        php_sxe_object  *sxe;
01067        char            *name;
01068        xmlNodePtr       node;
01069        xmlAttrPtr       attr;
01070        int              namelen;
01071        int              test;
01072 
01073        sxe = php_sxe_fetch_object(object TSRMLS_CC);
01074 
01075        if (is_debug) {
01076               ALLOC_HASHTABLE(rv);
01077               zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
01078        }
01079        else if (sxe->properties) {
01080               if (GC_G(gc_active)) {
01081                      return sxe->properties;
01082               }
01083               zend_hash_clean(sxe->properties);
01084               rv = sxe->properties;
01085        } else {
01086               if (GC_G(gc_active)) {
01087                      return NULL;
01088               }
01089               ALLOC_HASHTABLE(rv);
01090               zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
01091               sxe->properties = rv;
01092        }
01093 
01094        GET_NODE(sxe, node);
01095        if (!node) {
01096               return rv;
01097        }
01098        if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
01099               if (sxe->iter.type == SXE_ITER_ELEMENT) {
01100                      node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01101               }
01102               if (!node || node->type != XML_ENTITY_DECL) {
01103                      attr = node ? (xmlAttrPtr)node->properties : NULL;
01104                      zattr = NULL;
01105                      test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
01106                      while (attr) {
01107                             if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
01108                                    MAKE_STD_ZVAL(value);
01109                                    ZVAL_STRING(value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1), 0);
01110                                    namelen = xmlStrlen(attr->name) + 1;
01111                                    if (!zattr) {
01112                                           MAKE_STD_ZVAL(zattr);
01113                                           array_init(zattr);
01114                                           sxe_properties_add(rv, "@attributes", sizeof("@attributes"), zattr TSRMLS_CC);
01115                                    }
01116                                    add_assoc_zval_ex(zattr, (char*)attr->name, namelen, value);
01117                             }
01118                             attr = attr->next;
01119                      }
01120               }
01121        }
01122 
01123        GET_NODE(sxe, node);
01124        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01125        if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
01126               if (node->type == XML_ATTRIBUTE_NODE) {
01127                      MAKE_STD_ZVAL(value);
01128                      ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node->children, 1), 0);
01129                      zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
01130                      node = NULL;
01131               } else if (sxe->iter.type != SXE_ITER_CHILD) {
01132                      node = node->children;
01133               }
01134 
01135               while (node) {
01136                      if (node->children != NULL || node->prev != NULL || node->next != NULL) {
01137                             SKIP_TEXT(node);
01138                      } else {
01139                             if (node->type == XML_TEXT_NODE) {
01140                                    const xmlChar *cur = node->content;
01141                                    
01142                                    if (*cur != 0) {
01143                                           MAKE_STD_ZVAL(value);
01144                                           ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node, 1), 0);
01145                                           zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
01146                                    }
01147                                    goto next_iter;
01148                             }
01149                      }
01150 
01151                      if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
01152                             goto next_iter;
01153                      }
01154 
01155                      name = (char *) node->name;
01156                      if (!name) {
01157                             goto next_iter;
01158                      } else {
01159                             namelen = xmlStrlen(node->name) + 1;
01160                      }
01161 
01162                      _get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
01163 
01164                      sxe_properties_add(rv, name, namelen, value TSRMLS_CC);
01165 next_iter:
01166                      node = node->next;
01167               }
01168        }
01169 
01170        return rv;
01171 }
01172 /* }}} */
01173 
01174 static HashTable * sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */
01175 {
01176        return sxe_get_prop_hash(object, 0 TSRMLS_CC);
01177 }
01178 /* }}} */
01179 
01180 static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
01181 {
01182        *is_temp = 1;
01183        return sxe_get_prop_hash(object, 1 TSRMLS_CC);
01184 }
01185 /* }}} */
01186 
01187 static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */
01188 {
01189        php_sxe_object *sxe1;
01190        php_sxe_object *sxe2;
01191 
01192        sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
01193        sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
01194 
01195        if (sxe1->node == NULL) {
01196               if (sxe2->node) {
01197                      return 1;
01198               } else if (sxe1->document->ptr == sxe2->document->ptr) {
01199                      return 0;
01200               }
01201        } else {
01202               return !(sxe1->node == sxe2->node);
01203        }
01204        return 1;
01205 }
01206 /* }}} */
01207 
01208 /* {{{ proto array SimpleXMLElement::xpath(string path)
01209    Runs XPath query on the XML data */
01210 SXE_METHOD(xpath)
01211 {
01212        php_sxe_object    *sxe;
01213        zval              *value;
01214        char              *query;
01215        int                query_len;
01216        int                i;
01217        int                nsnbr = 0;
01218        xmlNsPtr          *ns = NULL;
01219        xmlXPathObjectPtr  retval;
01220        xmlNodeSetPtr      result;
01221        xmlNodePtr              nodeptr;
01222 
01223        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
01224               return;
01225        }
01226 
01227        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01228 
01229        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
01230               return; /* attributes don't have attributes */
01231        }
01232 
01233        if (!sxe->xpath) {
01234               sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
01235        }
01236        if (!sxe->node) {
01237               php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
01238        }
01239 
01240        nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC);
01241 
01242        sxe->xpath->node = nodeptr;
01243 
01244        ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
01245        if (ns != NULL) {
01246               while (ns[nsnbr] != NULL) {
01247                      nsnbr++;
01248               }
01249        }
01250 
01251        sxe->xpath->namespaces = ns;
01252        sxe->xpath->nsNr = nsnbr;
01253 
01254        retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
01255        if (ns != NULL) {
01256               xmlFree(ns);
01257               sxe->xpath->namespaces = NULL;
01258               sxe->xpath->nsNr = 0;
01259        }
01260 
01261        if (!retval) {
01262               RETURN_FALSE;
01263        }
01264 
01265        result = retval->nodesetval;
01266 
01267        array_init(return_value);
01268               
01269        if (result != NULL) {
01270               for (i = 0; i < result->nodeNr; ++i) {
01271                      nodeptr = result->nodeTab[i];
01272                      if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
01273                             MAKE_STD_ZVAL(value);
01279                             if (nodeptr->type == XML_TEXT_NODE) {
01280                                    _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
01281                             } else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
01282                                    _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC);
01283                             } else {
01284                                    _node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
01285                             }
01286 
01287                             add_next_index_zval(return_value, value);
01288                      }
01289               }
01290        }
01291 
01292        xmlXPathFreeObject(retval);
01293 }
01294 /* }}} */
01295 
01296 /* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
01297    Creates a prefix/ns context for the next XPath query */
01298 SXE_METHOD(registerXPathNamespace)
01299 {
01300        php_sxe_object    *sxe;
01301        int prefix_len, ns_uri_len;
01302        char *prefix, *ns_uri;
01303 
01304        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
01305               return;
01306        }
01307 
01308        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01309        if (!sxe->xpath) {
01310               sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
01311        }
01312 
01313        if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
01314               RETURN_FALSE
01315        }
01316        RETURN_TRUE;
01317 }
01318 
01319 /* }}} */
01320 
01321 /* {{{ proto string SimpleXMLElement::asXML([string filename])
01322    Return a well-formed XML string based on SimpleXML element */
01323 SXE_METHOD(asXML)
01324 {
01325        php_sxe_object     *sxe;
01326        xmlNodePtr          node;
01327        xmlOutputBufferPtr  outbuf;
01328        xmlChar            *strval;
01329        int                 strval_len;
01330        char               *filename;
01331        int                 filename_len;
01332 
01333        if (ZEND_NUM_ARGS() > 1) {
01334               RETURN_FALSE;
01335        }
01336 
01337        if (ZEND_NUM_ARGS() == 1) {
01338               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
01339                      RETURN_FALSE;
01340               }
01341 
01342               sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01343               GET_NODE(sxe, node);
01344               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01345 
01346               if (node) {
01347                      if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
01348                             int bytes;
01349                             bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
01350                             if (bytes == -1) {
01351                                    RETURN_FALSE;
01352                             } else {
01353                                    RETURN_TRUE;
01354                             }
01355                      } else {
01356                             outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
01357 
01358                             if (outbuf == NULL) {
01359                                    RETURN_FALSE;
01360                             }
01361 
01362                             xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
01363                             xmlOutputBufferClose(outbuf);
01364                             RETURN_TRUE;
01365                      }
01366               } else {
01367                      RETURN_FALSE;
01368               }
01369        }
01370 
01371        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01372        GET_NODE(sxe, node);
01373        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01374 
01375        if (node) {
01376               if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
01377                      xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding);
01378                      RETVAL_STRINGL((char *)strval, strval_len, 1);
01379                      xmlFree(strval);
01380               } else {
01381                      /* Should we be passing encoding information instead of NULL? */
01382                      outbuf = xmlAllocOutputBuffer(NULL);
01383 
01384                      if (outbuf == NULL) {
01385                             RETURN_FALSE;
01386                      }
01387 
01388                      xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
01389                      xmlOutputBufferFlush(outbuf);
01390                      RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1);
01391                      xmlOutputBufferClose(outbuf);
01392               }
01393        } else {
01394               RETVAL_FALSE;
01395        }
01396 }
01397 /* }}} */
01398 
01399 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
01400 
01401 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
01402 {
01403        char *prefix = SXE_NS_PREFIX(ns);
01404        if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) {
01405               add_assoc_string(return_value, prefix, (char*)ns->href, 1);
01406        }
01407 }
01408 /* }}} */
01409 
01410 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
01411 {
01412        xmlAttrPtr  attr;
01413 
01414        if (node->ns) {
01415               sxe_add_namespace_name(return_value, node->ns);
01416        }
01417 
01418        attr = node->properties;
01419        while (attr) {
01420               if (attr->ns) {
01421                      sxe_add_namespace_name(return_value, attr->ns);
01422               }
01423               attr = attr->next;
01424        }
01425 
01426        if (recursive) {
01427               node = node->children;
01428               while (node) {
01429                      if (node->type == XML_ELEMENT_NODE) {
01430                             sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
01431                      }
01432                      node = node->next;
01433               }
01434        }
01435 } /* }}} */
01436 
01437 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
01438    Return all namespaces in use */
01439 SXE_METHOD(getNamespaces)
01440 {
01441        zend_bool           recursive = 0;
01442        php_sxe_object     *sxe;
01443        xmlNodePtr          node;
01444 
01445        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
01446               return;
01447        }
01448 
01449        array_init(return_value);
01450 
01451        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01452        GET_NODE(sxe, node);
01453        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01454 
01455        if (node) {
01456               if (node->type == XML_ELEMENT_NODE) {
01457                      sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
01458               } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
01459                      sxe_add_namespace_name(return_value, node->ns);
01460               }
01461        }
01462 }
01463 /* }}} */
01464 
01465 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
01466 {
01467        xmlNsPtr ns;
01468 
01469        if (node->type == XML_ELEMENT_NODE) {
01470               ns = node->nsDef;
01471               while (ns != NULL) {
01472                      sxe_add_namespace_name(return_value, ns);
01473                      ns = ns->next;
01474               }
01475               if (recursive) {
01476                      node = node->children;
01477                      while (node) {
01478                             sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
01479                             node = node->next;
01480                      }
01481               }
01482        }
01483 }
01484 /* }}} */
01485 
01486 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive])
01487    Return all namespaces registered with document */
01488 SXE_METHOD(getDocNamespaces)
01489 {
01490        zend_bool           recursive = 0;
01491        php_sxe_object     *sxe;
01492 
01493        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
01494               return;
01495        }
01496 
01497        array_init(return_value);
01498 
01499        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01500 
01501        sxe_add_registered_namespaces(sxe, xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr), recursive, return_value TSRMLS_CC);
01502 }
01503 /* }}} */
01504 
01505 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
01506    Finds children of given node */
01507 SXE_METHOD(children)
01508 {
01509        php_sxe_object *sxe;
01510        char           *nsprefix = NULL;
01511        int             nsprefix_len = 0;
01512        xmlNodePtr      node;
01513        zend_bool       isprefix = 0;
01514 
01515        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
01516               return;
01517        }
01518 
01519        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01520 
01521        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
01522               return; /* attributes don't have attributes */
01523        }
01524 
01525        GET_NODE(sxe, node);
01526        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01527 
01528        _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
01529 
01530 }
01531 /* }}} */
01532 
01533 /* {{{ proto object SimpleXMLElement::getName()
01534    Finds children of given node */
01535 SXE_METHOD(getName)
01536 {
01537        php_sxe_object *sxe;
01538        xmlNodePtr      node;
01539        int             namelen;
01540 
01541        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01542 
01543        GET_NODE(sxe, node);
01544        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01545        if (node) {
01546               namelen = xmlStrlen(node->name);
01547               RETURN_STRINGL((char*)node->name, namelen, 1);
01548        } else {
01549               RETURN_EMPTY_STRING();
01550        }
01551 }
01552 /* }}} */
01553 
01554 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
01555    Identifies an element's attributes */
01556 SXE_METHOD(attributes)
01557 {
01558        php_sxe_object *sxe;
01559        char           *nsprefix = NULL;
01560        int             nsprefix_len = 0;
01561        xmlNodePtr      node;
01562        zend_bool       isprefix = 0;
01563 
01564        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
01565               return;
01566        }
01567 
01568        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01569        GET_NODE(sxe, node);
01570 
01571        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
01572               return; /* attributes don't have attributes */
01573        }
01574 
01575        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01576 
01577        _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
01578 }
01579 /* }}} */
01580 
01581 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
01582    Add Element with optional namespace information */
01583 SXE_METHOD(addChild)
01584 {
01585        php_sxe_object *sxe;
01586        char           *qname, *value = NULL, *nsuri = NULL;
01587        int             qname_len, value_len = 0, nsuri_len = 0;
01588        xmlNodePtr      node, newnode;
01589        xmlNsPtr        nsptr = NULL;
01590        xmlChar        *localname, *prefix = NULL;
01591 
01592        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
01593               &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
01594               return;
01595        }
01596 
01597        if (qname_len == 0) {
01598               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
01599               return;
01600        }
01601 
01602        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01603        GET_NODE(sxe, node);
01604 
01605        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
01606               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
01607               return;
01608        }
01609 
01610        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01611 
01612        if (node == NULL) {
01613               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
01614               return;
01615        }
01616 
01617        localname = xmlSplitQName2((xmlChar *)qname, &prefix);
01618        if (localname == NULL) {
01619               localname = xmlStrdup((xmlChar *)qname);
01620        }
01621 
01622        newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
01623 
01624        if (nsuri != NULL) {
01625               if (nsuri_len == 0) {
01626                      newnode->ns = NULL;
01627                      nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
01628               } else {
01629                      nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
01630                      if (nsptr == NULL) {
01631                             nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
01632                      }
01633                      newnode->ns = nsptr;
01634               }
01635        }
01636 
01637        _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
01638 
01639        xmlFree(localname);
01640        if (prefix != NULL) {
01641               xmlFree(prefix);
01642        }
01643 }
01644 /* }}} */
01645 
01646 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
01647    Add Attribute with optional namespace information */
01648 SXE_METHOD(addAttribute)
01649 {
01650        php_sxe_object *sxe;
01651        char           *qname, *value = NULL, *nsuri = NULL;
01652        int             qname_len, value_len = 0, nsuri_len = 0;
01653        xmlNodePtr      node;
01654        xmlAttrPtr      attrp = NULL;
01655        xmlNsPtr        nsptr = NULL;
01656        xmlChar        *localname, *prefix = NULL;
01657 
01658        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
01659               &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
01660               return;
01661        }
01662 
01663        if (qname_len == 0) {
01664               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
01665               return;
01666        }
01667 
01668        sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01669        GET_NODE(sxe, node);
01670 
01671        node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
01672 
01673        if (node && node->type != XML_ELEMENT_NODE) {
01674               node = node->parent;
01675        }
01676 
01677        if (node == NULL) {
01678               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
01679               return;
01680        }
01681 
01682        localname = xmlSplitQName2((xmlChar *)qname, &prefix);
01683        if (localname == NULL) {
01684               if (nsuri_len > 0) {
01685                      if (prefix != NULL) {
01686                             xmlFree(prefix);
01687                      }
01688                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
01689                      return;
01690               }
01691               localname = xmlStrdup((xmlChar *)qname);
01692        }
01693 
01694        attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
01695        if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
01696               xmlFree(localname);
01697               if (prefix != NULL) {
01698                      xmlFree(prefix);
01699               }
01700               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
01701               return;
01702        }
01703 
01704        if (nsuri != NULL) {
01705               nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
01706               if (nsptr == NULL) {
01707                      nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
01708               }
01709        }
01710 
01711        attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
01712 
01713        xmlFree(localname);
01714        if (prefix != NULL) {
01715               xmlFree(prefix);
01716        }
01717 }
01718 /* }}} */
01719 
01720 /* {{{ cast_object()
01721  */
01722 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
01723 {
01724        if (contents) {
01725               ZVAL_STRINGL(object, contents, strlen(contents), 1);
01726        } else {
01727               ZVAL_NULL(object);
01728        }
01729        Z_SET_REFCOUNT_P(object, 1);
01730        Z_UNSET_ISREF_P(object);
01731 
01732        switch (type) {
01733               case IS_STRING:
01734                      convert_to_string(object);
01735                      break;
01736               case IS_BOOL:
01737                      convert_to_boolean(object);
01738                      break;
01739               case IS_LONG:
01740                      convert_to_long(object);
01741                      break;
01742               case IS_DOUBLE:
01743                      convert_to_double(object);
01744                      break;
01745               default:
01746                      return FAILURE;
01747        }
01748        return SUCCESS;
01749 }
01750 /* }}} */
01751 
01752 /* {{{ sxe_object_cast()
01753  */
01754 static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
01755 {
01756        php_sxe_object *sxe;
01757        xmlChar           *contents = NULL;
01758        xmlNodePtr        node;
01759        int rv;
01760        HashTable      *prop_hash;
01761 
01762        sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
01763 
01764        if (type == IS_BOOL) {
01765               node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
01766               prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
01767               INIT_PZVAL(writeobj);
01768               ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
01769               zend_hash_destroy(prop_hash);
01770               efree(prop_hash);
01771               return SUCCESS;
01772        }
01773 
01774        if (sxe->iter.type != SXE_ITER_NONE) {
01775               node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
01776               if (node) {
01777                      contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
01778               }
01779        } else {
01780               if (!sxe->node) {
01781                      if (sxe->document) {
01782                             php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
01783                      }
01784               }
01785 
01786               if (sxe->node && sxe->node->node) {
01787                      if (sxe->node->node->children) {
01788                             contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
01789                      }
01790               }
01791        }
01792 
01793        if (readobj == writeobj) {
01794               INIT_PZVAL(writeobj);
01795               zval_dtor(readobj);
01796        }
01797 
01798        rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
01799 
01800        if (contents) {
01801               xmlFree(contents);
01802        }
01803        return rv;
01804 }
01805 /* }}} */
01806 
01807 /* {{{ proto object SimpleXMLElement::__toString() U
01808    Returns the string content */
01809 SXE_METHOD(__toString)
01810 {
01811        zval           *result;
01812 
01813        ALLOC_INIT_ZVAL(result);
01814 
01815        if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) {
01816               RETURN_ZVAL(result, 1, 1);
01817        } else {
01818               zval_ptr_dtor(&result);
01819               RETURN_EMPTY_STRING();
01820        }
01821 }
01822 /* }}} */
01823 
01824 static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */
01825 {
01826        xmlNodePtr       node;
01827        zval            *data;
01828 
01829        *count = 0;
01830 
01831        data = sxe->iter.data;
01832        sxe->iter.data = NULL;
01833 
01834        node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
01835 
01836        while (node)
01837        {
01838               (*count)++;
01839               node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
01840        }
01841 
01842        if (sxe->iter.data) {
01843               zval_ptr_dtor(&sxe->iter.data);
01844        }
01845        sxe->iter.data = data;
01846 
01847        return SUCCESS;
01848 }
01849 /* }}} */
01850 
01851 static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
01852 {
01853        php_sxe_object  *intern;
01854        intern = php_sxe_fetch_object(object TSRMLS_CC);
01855        if (intern->fptr_count) {
01856               zval *rv;
01857               zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv);
01858               if (rv) {
01859                      if (intern->tmp) {
01860                             zval_ptr_dtor(&intern->tmp);
01861                      }
01862                      MAKE_STD_ZVAL(intern->tmp);
01863                      ZVAL_ZVAL(intern->tmp, rv, 1, 1);
01864                      convert_to_long(intern->tmp);
01865                      *count = (long) Z_LVAL_P(intern->tmp);
01866                      return SUCCESS;
01867               }
01868               return FAILURE;
01869        }
01870        return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
01871 }
01872 /* }}} */
01873 
01874 /* {{{ proto int SimpleXMLElement::count()
01875  Get number of child elements */
01876 SXE_METHOD(count)
01877 {
01878        long count = 0;
01879        php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
01880 
01881        if (zend_parse_parameters_none() == FAILURE) {
01882               return;
01883        }
01884 
01885        php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
01886        
01887        RETURN_LONG(count);
01888 }
01889 /* }}} */
01890 
01891 static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */
01892 {
01893        zval *retval;
01894 
01895        MAKE_STD_ZVAL(retval);
01896 
01897        if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) {
01898               zend_error(E_ERROR, "Unable to cast node to string");
01899               /* FIXME: Should not be fatal */
01900        }
01901 
01902        Z_SET_REFCOUNT_P(retval, 0);
01903        return retval;
01904 }
01905 /* }}} */
01906 
01907 static zend_object_handlers sxe_object_handlers = { /* {{{ */
01908        ZEND_OBJECTS_STORE_HANDLERS,
01909        sxe_property_read,
01910        sxe_property_write,
01911        sxe_dimension_read,
01912        sxe_dimension_write,
01913        sxe_property_get_adr,
01914        sxe_get_value,                     /* get */
01915        NULL,
01916        sxe_property_exists,
01917        sxe_property_delete,
01918        sxe_dimension_exists,
01919        sxe_dimension_delete,
01920        sxe_get_properties,
01921        NULL, /* zend_get_std_object_handlers()->get_method,*/
01922        NULL, /* zend_get_std_object_handlers()->call_method,*/
01923        NULL, /* zend_get_std_object_handlers()->get_constructor, */
01924        NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
01925        NULL, /* zend_get_std_object_handlers()->get_class_name,*/
01926        sxe_objects_compare,
01927        sxe_object_cast,
01928        sxe_count_elements,
01929        sxe_get_debug_info
01930 };
01931 /* }}} */
01932 
01933 /* {{{ sxe_object_clone()
01934  */
01935 static void
01936 sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
01937 {
01938        php_sxe_object *sxe = (php_sxe_object *) object;
01939        php_sxe_object *clone;
01940        xmlNodePtr nodep = NULL;
01941        xmlDocPtr docp = NULL;
01942 
01943        clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
01944        clone->document = sxe->document;
01945        if (clone->document) {
01946               clone->document->refcount++;
01947               docp = clone->document->ptr;
01948        }
01949 
01950        clone->iter.isprefix = sxe->iter.isprefix;
01951        if (sxe->iter.name != NULL) {
01952               clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
01953        }
01954        if (sxe->iter.nsprefix != NULL) {
01955               clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
01956        }
01957        clone->iter.type = sxe->iter.type;
01958 
01959        if (sxe->node) {
01960               nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
01961        }
01962 
01963        php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
01964 
01965        *clone_ptr = (void *) clone;
01966 }
01967 /* }}} */
01968 
01969 /* {{{ sxe_object_dtor()
01970  */
01971 static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
01972 {
01973        /* dtor required to cleanup iterator related data properly */
01974 
01975        php_sxe_object *sxe;
01976 
01977        sxe = (php_sxe_object *) object;
01978 
01979        if (sxe->iter.data) {
01980               zval_ptr_dtor(&sxe->iter.data);
01981               sxe->iter.data = NULL;
01982        }
01983 
01984        if (sxe->iter.name) {
01985               xmlFree(sxe->iter.name);
01986               sxe->iter.name = NULL;
01987        }
01988        if (sxe->iter.nsprefix) {
01989               xmlFree(sxe->iter.nsprefix);
01990               sxe->iter.nsprefix = NULL;
01991        }
01992        if (sxe->tmp) {
01993               zval_ptr_dtor(&sxe->tmp);
01994               sxe->tmp = NULL;
01995        }
01996 }
01997 /* }}} */
01998 
01999 /* {{{ sxe_object_free_storage()
02000  */
02001 static void sxe_object_free_storage(void *object TSRMLS_DC)
02002 {
02003        php_sxe_object *sxe;
02004 
02005        sxe = (php_sxe_object *) object;
02006 
02007 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
02008        zend_object_std_dtor(&sxe->zo TSRMLS_CC);
02009 #else
02010        if (sxe->zo.guards) {
02011               zend_hash_destroy(sxe->zo.guards);
02012               FREE_HASHTABLE(sxe->zo.guards);
02013        }
02014 
02015        if (sxe->zo.properties) {
02016               zend_hash_destroy(sxe->zo.properties);
02017               FREE_HASHTABLE(sxe->zo.properties);
02018        }
02019 #endif
02020 
02021        php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
02022 
02023        if (sxe->xpath) {
02024               xmlXPathFreeContext(sxe->xpath);
02025        }
02026 
02027        if (sxe->properties) {
02028               zend_hash_destroy(sxe->properties);
02029               FREE_HASHTABLE(sxe->properties);
02030        }
02031 
02032        efree(object);
02033 }
02034 /* }}} */
02035 
02036 /* {{{ php_sxe_object_new()
02037  */
02038 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
02039 {
02040        php_sxe_object *intern;
02041        zend_class_entry     *parent = ce;
02042        int inherited = 0;
02043 
02044        intern = ecalloc(1, sizeof(php_sxe_object));
02045 
02046        intern->iter.type = SXE_ITER_NONE;
02047        intern->iter.nsprefix = NULL;
02048        intern->iter.name = NULL;
02049        intern->fptr_count = NULL;
02050 
02051 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
02052        zend_object_std_init(&intern->zo, ce TSRMLS_CC);
02053 #else
02054        ALLOC_HASHTABLE(intern->zo.properties);
02055        zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
02056 
02057        intern->zo.ce = ce;
02058        intern->zo.guards = NULL;
02059 #endif
02060 
02061        while (parent) {
02062               if (parent == sxe_class_entry) {
02063                      break;
02064               }
02065 
02066               parent = parent->parent;
02067               inherited = 1;
02068        }
02069 
02070        if (inherited) {
02071               zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count);
02072               if (intern->fptr_count->common.scope == parent) {
02073                      intern->fptr_count = NULL;
02074               }
02075        }
02076 
02077        return intern;
02078 }
02079 /* }}} */
02080 
02081 /* {{{ php_sxe_register_object
02082  */
02083 static zend_object_value
02084 php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
02085 {
02086        zend_object_value rv;
02087 
02088        rv.handle = zend_objects_store_put(intern, sxe_object_dtor, (zend_objects_free_object_storage_t)sxe_object_free_storage, sxe_object_clone TSRMLS_CC);
02089        rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
02090 
02091        return rv;
02092 }
02093 /* }}} */
02094 
02095 /* {{{ sxe_object_new()
02096  */
02097 PHP_SXE_API zend_object_value
02098 sxe_object_new(zend_class_entry *ce TSRMLS_DC)
02099 {
02100        php_sxe_object    *intern;
02101 
02102        intern = php_sxe_object_new(ce TSRMLS_CC);
02103        return php_sxe_register_object(intern TSRMLS_CC);
02104 }
02105 /* }}} */
02106 
02107 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
02108    Load a filename and return a simplexml_element object to allow for processing */
02109 PHP_FUNCTION(simplexml_load_file)
02110 {
02111        php_sxe_object *sxe;
02112        char           *filename;
02113        int             filename_len;
02114        xmlDocPtr       docp;
02115        char           *ns = NULL;
02116        int             ns_len = 0;
02117        long            options = 0;
02118        zend_class_entry *ce= sxe_class_entry;
02119        zend_bool       isprefix = 0;
02120 
02121        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
02122               return;
02123        }
02124 
02125        docp = xmlReadFile(filename, NULL, options);
02126 
02127        if (! docp) {
02128               RETURN_FALSE;
02129        }
02130 
02131        if (!ce) {
02132               ce = sxe_class_entry;
02133        }
02134        sxe = php_sxe_object_new(ce TSRMLS_CC);
02135        sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
02136        sxe->iter.isprefix = isprefix;
02137        php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
02138        php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
02139 
02140        return_value->type = IS_OBJECT;
02141        return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
02142 }
02143 /* }}} */
02144 
02145 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
02146    Load a string and return a simplexml_element object to allow for processing */
02147 PHP_FUNCTION(simplexml_load_string)
02148 {
02149        php_sxe_object *sxe;
02150        char           *data;
02151        int             data_len;
02152        xmlDocPtr       docp;
02153        char           *ns = NULL;
02154        int             ns_len = 0;
02155        long            options = 0;
02156        zend_class_entry *ce= sxe_class_entry;
02157        zend_bool       isprefix = 0;
02158 
02159        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
02160               return;
02161        }
02162 
02163        docp = xmlReadMemory(data, data_len, NULL, NULL, options);
02164 
02165        if (! docp) {
02166               RETURN_FALSE;
02167        }
02168 
02169        if (!ce) {
02170               ce = sxe_class_entry;
02171        }
02172        sxe = php_sxe_object_new(ce TSRMLS_CC);
02173        sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
02174        sxe->iter.isprefix = isprefix;
02175        php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
02176        php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
02177 
02178        return_value->type = IS_OBJECT;
02179        return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
02180 }
02181 /* }}} */
02182 
02183 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
02184    SimpleXMLElement constructor */
02185 SXE_METHOD(__construct)
02186 {
02187        php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
02188        char           *data, *ns = NULL;
02189        int             data_len, ns_len = 0;
02190        xmlDocPtr       docp;
02191        long            options = 0;
02192        zend_bool       is_url = 0, isprefix = 0;
02193        zend_error_handling error_handling;
02194 
02195        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
02196        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
02197               zend_restore_error_handling(&error_handling TSRMLS_CC);
02198               return;
02199        }
02200 
02201        zend_restore_error_handling(&error_handling TSRMLS_CC);
02202 
02203        docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
02204 
02205        if (!docp) {
02206               ((php_libxml_node_object *)sxe)->document = NULL;
02207               zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
02208               return;
02209        }
02210 
02211        sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
02212        sxe->iter.isprefix = isprefix;
02213        php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
02214        php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
02215 }
02216 /* }}} */
02217 
02218 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
02219        php_sxe_iterator_dtor,
02220        php_sxe_iterator_valid,
02221        php_sxe_iterator_current_data,
02222        php_sxe_iterator_current_key,
02223        php_sxe_iterator_move_forward,
02224        php_sxe_iterator_rewind,
02225 };
02226 /* }}} */
02227 
02228 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
02229 {
02230        xmlChar *prefix  = sxe->iter.nsprefix;
02231        int isprefix  = sxe->iter.isprefix;
02232        int test_elem = sxe->iter.type == SXE_ITER_ELEMENT  && sxe->iter.name;
02233        int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
02234 
02235        while (node) {
02236               SKIP_TEXT(node);
02237               if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
02238                      if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
02239                             break;
02240                      }
02241               } else if (node->type == XML_ATTRIBUTE_NODE) {
02242                      if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
02243                             break;
02244                      }
02245               }
02246 next_iter:
02247               node = node->next;
02248        }
02249 
02250        if (node && use_data) {
02251               ALLOC_INIT_ZVAL(sxe->iter.data);
02252               _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
02253        }
02254 
02255        return node;
02256 }
02257 /* }}} */
02258 
02259 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
02260 {
02261        xmlNodePtr node;
02262 
02263        if (sxe->iter.data) {
02264               zval_ptr_dtor(&sxe->iter.data);
02265               sxe->iter.data = NULL;
02266        }
02267 
02268        GET_NODE(sxe, node)
02269 
02270        if (node) {
02271               switch (sxe->iter.type) {
02272                      case SXE_ITER_ELEMENT:
02273                      case SXE_ITER_CHILD:
02274                      case SXE_ITER_NONE:
02275                             node = node->children;
02276                             break;
02277                      case SXE_ITER_ATTRLIST:
02278                             node = (xmlNodePtr) node->properties;
02279               }
02280               return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
02281        }
02282        return NULL;
02283 }
02284 /* }}} */
02285 
02286 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
02287 {
02288        php_sxe_iterator *iterator;
02289 
02290        if (by_ref) {
02291               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
02292        }
02293        iterator = emalloc(sizeof(php_sxe_iterator));
02294 
02295        Z_ADDREF_P(object);
02296        iterator->intern.data = (void*)object;
02297        iterator->intern.funcs = &php_sxe_iterator_funcs;
02298        iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
02299 
02300        return (zend_object_iterator*)iterator;
02301 }
02302 /* }}} */
02303 
02304 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
02305 {
02306        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02307 
02308        /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
02309        if (iterator->intern.data) {
02310               zval_ptr_dtor((zval**)&iterator->intern.data);
02311        }
02312 
02313        efree(iterator);
02314 }
02315 /* }}} */
02316 
02317 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
02318 {
02319        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02320 
02321        return iterator->sxe->iter.data ? SUCCESS : FAILURE;
02322 }
02323 /* }}} */
02324 
02325 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
02326 {
02327        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02328 
02329        *data = &iterator->sxe->iter.data;
02330 }
02331 /* }}} */
02332 
02333 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
02334 {
02335        zval *curobj;
02336        xmlNodePtr curnode = NULL;
02337        php_sxe_object *intern;
02338        int namelen;
02339 
02340        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02341        curobj = iterator->sxe->iter.data;
02342 
02343        intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
02344        if (intern != NULL && intern->node != NULL) {
02345               curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
02346        }
02347        if (!curnode) {
02348               return HASH_KEY_NON_EXISTANT;
02349        }
02350 
02351        namelen = xmlStrlen(curnode->name);
02352        *str_key = estrndup((char *)curnode->name, namelen);
02353        *str_key_len = namelen + 1;
02354        return HASH_KEY_IS_STRING;
02355 
02356 }
02357 /* }}} */
02358 
02359 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
02360 {
02361        xmlNodePtr      node = NULL;
02362        php_sxe_object  *intern;
02363 
02364        if (sxe->iter.data) {
02365               intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
02366               GET_NODE(intern, node)
02367               zval_ptr_dtor(&sxe->iter.data);
02368               sxe->iter.data = NULL;
02369        }
02370 
02371        if (node) {
02372               php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
02373        }
02374 }
02375 /* }}} */
02376 
02377 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
02378 {
02379        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02380        php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
02381 }
02382 /* }}} */
02383 
02384 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
02385 {
02386        php_sxe_object       *sxe;
02387 
02388        php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
02389        sxe = iterator->sxe;
02390 
02391        php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
02392 }
02393 /* }}} */
02394 
02395 void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
02396 {
02397        php_sxe_object *sxe;
02398        xmlNodePtr node;
02399 
02400        sxe = php_sxe_fetch_object(object TSRMLS_CC);
02401        GET_NODE(sxe, node);
02402        return php_sxe_get_first_node(sxe, node TSRMLS_CC);
02403 }
02404 /* }}} */
02405 
02406 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
02407    Get a simplexml_element object from dom to allow for processing */
02408 PHP_FUNCTION(simplexml_import_dom)
02409 {
02410        php_sxe_object *sxe;
02411        zval *node;
02412        php_libxml_node_object *object;
02413        xmlNodePtr           nodep = NULL;
02414        zend_class_entry *ce= sxe_class_entry;
02415 
02416        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
02417               return;
02418        }
02419 
02420        object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
02421 
02422        nodep = php_libxml_import_node(node TSRMLS_CC);
02423 
02424        if (nodep) {
02425               if (nodep->doc == NULL) {
02426                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
02427                      RETURN_NULL();
02428               }
02429               if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
02430                      nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
02431               }
02432        }
02433 
02434        if (nodep && nodep->type == XML_ELEMENT_NODE) {
02435               if (!ce) {
02436                      ce = sxe_class_entry;
02437               }
02438               sxe = php_sxe_object_new(ce TSRMLS_CC);
02439               sxe->document = object->document;
02440               php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
02441               php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
02442 
02443               return_value->type = IS_OBJECT;
02444               return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
02445        } else {
02446               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
02447               RETVAL_NULL();
02448        }
02449 }
02450 /* }}} */
02451 
02452 /* {{{ arginfo */
02453 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
02454        ZEND_ARG_INFO(0, filename)
02455        ZEND_ARG_INFO(0, class_name)
02456        ZEND_ARG_INFO(0, options)
02457        ZEND_ARG_INFO(0, ns)
02458        ZEND_ARG_INFO(0, is_prefix)
02459 ZEND_END_ARG_INFO()
02460 
02461 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
02462        ZEND_ARG_INFO(0, data)
02463        ZEND_ARG_INFO(0, class_name)
02464        ZEND_ARG_INFO(0, options)
02465        ZEND_ARG_INFO(0, ns)
02466        ZEND_ARG_INFO(0, is_prefix)
02467 ZEND_END_ARG_INFO()
02468 
02469 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
02470        ZEND_ARG_INFO(0, node)
02471        ZEND_ARG_INFO(0, class_name)
02472 ZEND_END_ARG_INFO()
02473 
02474 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
02475        ZEND_ARG_INFO(0, path)
02476 ZEND_END_ARG_INFO()
02477 
02478 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
02479        ZEND_ARG_INFO(0, prefix)
02480        ZEND_ARG_INFO(0, ns)
02481 ZEND_END_ARG_INFO()
02482 
02483 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
02484        ZEND_ARG_INFO(0, filename)
02485 ZEND_END_ARG_INFO()
02486 
02487 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
02488        ZEND_ARG_INFO(0, recursve)
02489 ZEND_END_ARG_INFO()
02490 
02491 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
02492        ZEND_ARG_INFO(0, ns)
02493        ZEND_ARG_INFO(0, is_prefix)
02494 ZEND_END_ARG_INFO()
02495 
02496 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
02497        ZEND_ARG_INFO(0, data)
02498        ZEND_ARG_INFO(0, options)
02499        ZEND_ARG_INFO(0, data_is_url)
02500        ZEND_ARG_INFO(0, ns)
02501        ZEND_ARG_INFO(0, is_prefix)
02502 ZEND_END_ARG_INFO()
02503 
02504 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
02505 ZEND_END_ARG_INFO()
02506 
02507 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
02508        ZEND_ARG_INFO(0, name)
02509        ZEND_ARG_INFO(0, value)
02510        ZEND_ARG_INFO(0, ns)
02511 ZEND_END_ARG_INFO()
02512 /* }}} */
02513 
02514 const zend_function_entry simplexml_functions[] = { /* {{{ */
02515        PHP_FE(simplexml_load_file,        arginfo_simplexml_load_file)
02516        PHP_FE(simplexml_load_string,      arginfo_simplexml_load_string)
02517        PHP_FE(simplexml_import_dom,       arginfo_simplexml_import_dom)
02518        PHP_FE_END
02519 };
02520 /* }}} */
02521 
02522 static const zend_module_dep simplexml_deps[] = { /* {{{ */
02523        ZEND_MOD_REQUIRED("libxml")
02524        ZEND_MOD_REQUIRED("spl")
02525        ZEND_MOD_END
02526 };
02527 /* }}} */
02528 
02529 zend_module_entry simplexml_module_entry = { /* {{{ */
02530        STANDARD_MODULE_HEADER_EX, NULL,
02531        simplexml_deps,
02532        "SimpleXML",
02533        simplexml_functions,
02534        PHP_MINIT(simplexml),
02535        PHP_MSHUTDOWN(simplexml),
02536        NULL,
02537        NULL,
02538        PHP_MINFO(simplexml),
02539        "0.1",
02540        STANDARD_MODULE_PROPERTIES
02541 };
02542 /* }}} */
02543 
02544 #ifdef COMPILE_DL_SIMPLEXML
02545 ZEND_GET_MODULE(simplexml)
02546 #endif
02547 
02548 /* the method table */
02549 /* each method can have its own parameters and visibility */
02550 static const zend_function_entry sxe_functions[] = { /* {{{ */
02551        SXE_ME(__construct,            arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
02552        SXE_ME(asXML,                  arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
02553        SXE_MALIAS(saveXML, asXML,     arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
02554        SXE_ME(xpath,                  arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
02555        SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
02556        SXE_ME(attributes,             arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
02557        SXE_ME(children,               arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
02558        SXE_ME(getNamespaces,          arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
02559        SXE_ME(getDocNamespaces,       arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
02560        SXE_ME(getName,                arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
02561        SXE_ME(addChild,               arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
02562        SXE_ME(addAttribute,           arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
02563        SXE_ME(__toString,             arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
02564        SXE_ME(count,                  arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
02565        PHP_FE_END
02566 };
02567 /* }}} */
02568 
02569 /* {{{ PHP_MINIT_FUNCTION(simplexml)
02570  */
02571 PHP_MINIT_FUNCTION(simplexml)
02572 {
02573        zend_class_entry sxe;
02574 
02575        INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
02576        sxe.create_object = sxe_object_new;
02577        sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
02578        sxe_class_entry->get_iterator = php_sxe_get_iterator;
02579        sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
02580        zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
02581        sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
02582        sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
02583        sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
02584        sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
02585        sxe_class_entry->serialize = zend_class_serialize_deny;
02586        sxe_class_entry->unserialize = zend_class_unserialize_deny;
02587 
02588        php_libxml_register_export(sxe_class_entry, simplexml_export_node);
02589 
02590        PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
02591 
02592        return SUCCESS;
02593 }
02594 /* }}} */
02595 
02596 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
02597  */
02598 PHP_MSHUTDOWN_FUNCTION(simplexml)
02599 {
02600        sxe_class_entry = NULL;
02601        return SUCCESS;
02602 }
02603 /* }}} */
02604 
02605 /* {{{ PHP_MINFO_FUNCTION(simplexml)
02606  */
02607 PHP_MINFO_FUNCTION(simplexml)
02608 {
02609        php_info_print_table_start();
02610        php_info_print_table_header(2, "Simplexml support", "enabled");
02611        php_info_print_table_row(2, "Revision", "$Revision: 321634 $");
02612        php_info_print_table_row(2, "Schema support",
02613 #ifdef LIBXML_SCHEMAS_ENABLED
02614               "enabled");
02615 #else
02616               "not available");
02617 #endif
02618        php_info_print_table_end();
02619 }
02620 /* }}} */
02621 
02622 #endif
02623