diff options
-rw-r--r-- | ext/simplexml/php_simplexml.h | 6 | ||||
-rw-r--r-- | ext/simplexml/simplexml.c | 323 | ||||
-rwxr-xr-x | ext/simplexml/tests/006.phpt | 21 | ||||
-rwxr-xr-x | ext/simplexml/tests/006.xml | 3 |
4 files changed, 235 insertions, 118 deletions
diff --git a/ext/simplexml/php_simplexml.h b/ext/simplexml/php_simplexml.h index 1b325ca9cd..146a818578 100644 --- a/ext/simplexml/php_simplexml.h +++ b/ext/simplexml/php_simplexml.h @@ -64,6 +64,12 @@ typedef struct { HashTable *properties; simplexml_nsmap *nsmapptr; xmlXPathContextPtr xpath; + struct { + xmlNodePtr node; + char *name; + int namelen; + zval *data; + } iter; } php_sxe_object; diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 9012134019..acd138303c 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -30,8 +30,17 @@ #include "ext/standard/info.h" #include "php_simplexml.h" +#if HAVE_SPL +#include "ext/spl/spl_iterators.h" +#endif + + zend_class_entry *sxe_class_entry; +#define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags) + +#define SXE_METHOD(func) PHP_METHOD(simplexml_element, func) + #define SKIP_TEXT(__p) \ if ((__p)->type == XML_TEXT_NODE) { \ goto next_iter; \ @@ -51,8 +60,7 @@ php_sxe_fetch_object(zval *object TSRMLS_DC) /* {{{ _node_as_zval() */ -static void -_node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value TSRMLS_DC) +static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value TSRMLS_DC) { php_sxe_object *subnode; @@ -118,8 +126,7 @@ match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name) /* {{{ sxe_prop_dim_read() */ -static zval * -sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, zend_bool silent TSRMLS_DC) +static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, zend_bool silent TSRMLS_DC) { zval *return_value; zval *value = NULL; @@ -224,8 +231,7 @@ next_iter: /* {{{ sxe_property_read() */ -static zval * -sxe_property_read(zval *object, zval *member, zend_bool silent TSRMLS_DC) +static zval * sxe_property_read(zval *object, zval *member, zend_bool silent TSRMLS_DC) { return sxe_prop_dim_read(object, member, 1, 0, silent TSRMLS_CC); } @@ -233,7 +239,7 @@ sxe_property_read(zval *object, zval *member, zend_bool silent TSRMLS_DC) /* {{{ sxe_dimension_read() */ -static zval *sxe_dimension_read(zval *object, zval *offset TSRMLS_DC) +static zval * sxe_dimension_read(zval *object, zval *offset TSRMLS_DC) { return sxe_prop_dim_read(object, offset, 0, 1, 0 TSRMLS_CC); } @@ -641,10 +647,9 @@ sxe_method_get(zval *object, char *name, int len TSRMLS_DC) } /* }}} */ -/* {{{ simplexml_ce_xpath_search() - */ -static void -simplexml_ce_xpath_search(INTERNAL_FUNCTION_PARAMETERS) +/* {{{ xsearch() + */ +SXE_METHOD(xsearch) { php_sxe_object *sxe; zval *value; @@ -694,8 +699,7 @@ simplexml_ce_xpath_search(INTERNAL_FUNCTION_PARAMETERS) _node_as_zval(sxe, result->nodeTab[i], value TSRMLS_CC); } add_next_index_zval(return_value, value); - } - + } } /* }}} */ @@ -775,12 +779,26 @@ simplexml_ce_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) } /* }}} */ +/* {{{ validate_schema_file + */ +SXE_METHOD(validate_schema_file) +{ + simplexml_ce_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, SCHEMA_FILE); +} +/* }}} */ + +/* {{{ validate_schema_buffer + */ +SXE_METHOD(validate_schema_buffer) +{ + simplexml_ce_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, SCHEMA_BLOB); +} +/* }}} */ #endif /* {{{ simplexml_ce_register_ns() */ -static void -simplexml_ce_register_ns(INTERNAL_FUNCTION_PARAMETERS) +SXE_METHOD(register_ns) { php_sxe_object *sxe; char *nsname; @@ -800,8 +818,7 @@ simplexml_ce_register_ns(INTERNAL_FUNCTION_PARAMETERS) /* {{{ simplexml_ce_to_xml_string() */ -static void -simplexml_ce_to_xml_string(INTERNAL_FUNCTION_PARAMETERS) +SXE_METHOD(to_xml_string) { php_sxe_object *sxe; xmlChar *strval; @@ -822,8 +839,7 @@ simplexml_ce_to_xml_string(INTERNAL_FUNCTION_PARAMETERS) /* {{{ simplexml_ce_to_xml_file() */ -static void -simplexml_ce_to_xml_file(INTERNAL_FUNCTION_PARAMETERS) +SXE_METHOD(to_xml_file) { php_sxe_object *sxe; char *filename; @@ -841,54 +857,6 @@ simplexml_ce_to_xml_file(INTERNAL_FUNCTION_PARAMETERS) } /* }}} */ -/* {{{ sxe_call_method() - */ -static int -sxe_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) -{ - if (!strcmp(method, "xsearch")) { - simplexml_ce_xpath_search(INTERNAL_FUNCTION_PARAM_PASSTHRU); -#ifdef LIBXML_SCHEMAS_ENABLED - } else if (!strcmp(method, "validate_schema_file")) { - simplexml_ce_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, SCHEMA_FILE); - } else if (!strcmp(method, "validate_schema_buffer")) { - simplexml_ce_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, SCHEMA_BLOB); -#endif - } else if (!strcmp(method, "register_ns")) { - simplexml_ce_register_ns(INTERNAL_FUNCTION_PARAM_PASSTHRU); - } else if (!strcmp(method, "to_xml")) { - simplexml_ce_to_xml_string(INTERNAL_FUNCTION_PARAM_PASSTHRU); - } else if (!strcmp(method, "to_xml_file")) { - simplexml_ce_to_xml_file(INTERNAL_FUNCTION_PARAM_PASSTHRU); - } else { - return 0; - } - - return 1; -} -/* }}} */ - -/* {{{ sxe_class_entry_get() - */ -static zend_class_entry * -sxe_class_entry_get(zval *object TSRMLS_DC) -{ - return sxe_class_entry; -} -/* }}} */ - -/* {{{ sxe_class_name_get() - */ -static int -sxe_class_name_get(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) -{ - *class_name = estrdup("simplexml_element"); - *class_name_len = sizeof("simplexml_element")-1; - - return 0; -} -/* }}} */ - /* {{{ cast_object() */ static int @@ -1001,10 +969,10 @@ static zend_object_handlers sxe_object_handlers = { sxe_dimension_delete, sxe_properties_get, sxe_method_get, - sxe_call_method, + NULL, /* zend_get_std_object_handlers()->get_method,*/ sxe_constructor_get, - sxe_class_entry_get, - sxe_class_name_get, + NULL, /* zend_get_std_object_handlers()->get_class_entry,*/ + NULL, /* zend_get_std_object_handlers()->get_class_name,*/ sxe_objects_compare, sxe_object_cast }; @@ -1049,8 +1017,7 @@ _free_ns_entry(void *p, xmlChar *data) /* {{{ sxe_object_dtor() */ -static void -sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) +static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) { php_sxe_object *sxe; @@ -1059,6 +1026,10 @@ sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) zend_hash_destroy(sxe->zo.properties); FREE_HASHTABLE(sxe->zo.properties); + if (sxe->iter.data) { + zval_ptr_dtor(&sxe->iter.data); + } + php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC); if (--sxe->nsmapptr->refcount == 0) { @@ -1074,27 +1045,19 @@ sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) zend_hash_destroy(sxe->properties); FREE_HASHTABLE(sxe->properties); } - + efree(object); } /* }}} */ /* {{{ php_sxe_object_new() */ -static php_sxe_object * -php_sxe_object_new(TSRMLS_D) +static php_sxe_object* php_sxe_object_new(TSRMLS_D) { php_sxe_object *intern; intern = ecalloc(1, sizeof(php_sxe_object)); intern->zo.ce = sxe_class_entry; - intern->zo.in_get = 0; - intern->zo.in_set = 0; - intern->node = NULL; - intern->document = NULL; - intern->nsmapptr = NULL; - intern->xpath = NULL; - intern->properties = NULL; ALLOC_HASHTABLE(intern->zo.properties); zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); @@ -1192,10 +1155,6 @@ PHP_FUNCTION(simplexml_load_string) typedef struct { zend_object_iterator intern; php_sxe_object *sxe; - xmlNodePtr node; - char *name; - int namelen; - zval *data; } php_sxe_iterator; static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC); @@ -1203,6 +1162,7 @@ static int php_sxe_iterator_has_more(zend_object_iterator *iter TSRMLS_DC); static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC); +static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC); zend_object_iterator_funcs php_sxe_iterator_funcs = { php_sxe_iterator_dtor, @@ -1210,15 +1170,19 @@ zend_object_iterator_funcs php_sxe_iterator_funcs = { php_sxe_iterator_current_data, php_sxe_iterator_current_key, php_sxe_iterator_move_forward, - NULL + php_sxe_iterator_rewind, }; -static void php_sxe_iterator_current(php_sxe_iterator *iterator TSRMLS_DC) +static void php_sxe_iterator_current(php_sxe_object *sxe TSRMLS_DC) { xmlNodePtr node; - while (iterator->node) { - node = iterator->node; + if (sxe->iter.data) { + zval_ptr_dtor(&sxe->iter.data); + } + ALLOC_INIT_ZVAL(sxe->iter.data); + while (sxe->iter.node) { + node = sxe->iter.node; SKIP_TEXT(node); @@ -1230,17 +1194,16 @@ static void php_sxe_iterator_current(php_sxe_iterator *iterator TSRMLS_DC) } } while (0); - if (!iterator->node->name) { + if (!sxe->iter.node->name) { goto next_iter; } else { - iterator->namelen = xmlStrlen(node->name)+1; - iterator->name = (char *) node->name; - MAKE_STD_ZVAL(iterator->data); - _node_as_zval(iterator->sxe, node, iterator->data TSRMLS_CC); + sxe->iter.namelen = xmlStrlen(node->name)+1; + sxe->iter.name = (char *) node->name; + _node_as_zval(sxe, node, sxe->iter.data TSRMLS_CC); } break; next_iter: - iterator->node = iterator->node->next; + sxe->iter.node = sxe->iter.node->next; } } @@ -1252,10 +1215,6 @@ zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object TS iterator->intern.data = (void*)object; iterator->intern.funcs = &php_sxe_iterator_funcs; iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC); - GET_NODE(iterator->sxe, iterator->node); - iterator->node = iterator->node->children; - iterator->data = NULL; - php_sxe_iterator_current(iterator TSRMLS_CC); return (zend_object_iterator*)iterator; } @@ -1266,9 +1225,6 @@ static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) zval_ptr_dtor((zval**)&iterator->intern.data); - if (iterator->data) { - zval_ptr_dtor(&iterator->data); - } efree(iterator); } @@ -1276,37 +1232,147 @@ static int php_sxe_iterator_has_more(zend_object_iterator *iter TSRMLS_DC) { php_sxe_iterator *iterator = (php_sxe_iterator *)iter; - return iterator->node ? SUCCESS : FAILURE; + return iterator->sxe->iter.node ? SUCCESS : FAILURE; } static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) { php_sxe_iterator *iterator = (php_sxe_iterator *)iter; - - *data = &iterator->data; + + *data = &iterator->sxe->iter.data; } static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) { php_sxe_iterator *iterator = (php_sxe_iterator *)iter; - *str_key = estrndup(iterator->name, iterator->namelen-1); - *str_key_len = iterator->namelen; + *str_key = estrndup(iterator->sxe->iter.name, iterator->sxe->iter.namelen-1); + *str_key_len = iterator->sxe->iter.namelen; return HASH_KEY_IS_STRING; } static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) { php_sxe_iterator *iterator = (php_sxe_iterator *)iter; + + if (iterator->sxe->iter.node) { + iterator->sxe->iter.node = iterator->sxe->iter.node->next; + } + php_sxe_iterator_current(iterator->sxe TSRMLS_CC); +} + +static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + php_sxe_iterator *iterator = (php_sxe_iterator *)iter; - if (iterator->data) { - zval_ptr_dtor(&iterator->data); - iterator->data = NULL; + GET_NODE(iterator->sxe, iterator->sxe->iter.node); + if (iterator->sxe->iter.node) { + iterator->sxe->iter.node = iterator->sxe->iter.node->children; } - iterator->node = iterator->node->next; - php_sxe_iterator_current(iterator TSRMLS_CC); + php_sxe_iterator_current(iterator->sxe TSRMLS_CC); } +/* {{{ rewind() + */ +SXE_METHOD(rewind) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + + GET_NODE(sxe, sxe->iter.node); + if (sxe->iter.node) { + sxe->iter.node = sxe->iter.node->children; + } + php_sxe_iterator_current(sxe TSRMLS_CC); +} +/* }}} */ + +/* {{{ hasMore() + */ +SXE_METHOD(hasMore) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + + RETURN_BOOL(sxe->iter.node); +} +/* }}} */ + +/* {{{ curent() + */ +SXE_METHOD(current) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + + REPLACE_ZVAL_VALUE(&return_value, sxe->iter.data, 1); +} +/* }}} */ + +/* {{{ key() + */ +SXE_METHOD(key) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + + RETURN_STRINGL(sxe->iter.name, sxe->iter.namelen-1, 1); +} +/* }}} */ + +/* {{{ next() + */ +SXE_METHOD(next) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + + if (sxe->iter.node) { + sxe->iter.node = sxe->iter.node->next; + } + php_sxe_iterator_current(sxe TSRMLS_CC); +} +/* }}} */ + +/* {{{ hasChildren() + */ +SXE_METHOD(hasChildren) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + php_sxe_object *child = php_sxe_fetch_object(sxe->iter.data TSRMLS_CC); + xmlNodePtr node; + + GET_NODE(child, node); + if (node) { + node = node->children; + } + while (node) { + SKIP_TEXT(node); + + do if (node->ns) { + if (node->parent->ns) { + if (!xmlStrcmp(node->ns->href, node->parent->ns->href)) { + break; + } + } + } while (0); + if (node->type == XML_ELEMENT_NODE) { + break; + } +next_iter: + node = node->next; + } + RETURN_BOOL(node ? 1 : 0); +} +/* }}} */ + +/* {{{ getChildren() + */ +SXE_METHOD(getChildren) +{ + php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); + +// REPLACE_ZVAL_VALUE(&return_value, sxe->iter.data, 0); + return_value->type = IS_OBJECT; + return_value->value.obj = zend_objects_store_clone_obj(sxe->iter.data TSRMLS_CC); +} +/* }}} */ + /* {{{ proto simplemxml_element simplexml_import_dom(domNode node) Get a simplexml_element object from dom to allow for processing */ PHP_FUNCTION(simplexml_import_dom) @@ -1379,17 +1445,44 @@ zend_module_entry simplexml_module_entry = { #ifdef COMPILE_DL_SIMPLEXML ZEND_GET_MODULE(simplexml) #endif - + +/* the method table */ +/* each method can have its own parameters and visibility */ +static zend_function_entry sxe_functions[] = { + SXE_ME(register_ns, NULL, ZEND_ACC_PUBLIC) + SXE_ME(to_xml_file, NULL, ZEND_ACC_PUBLIC) + SXE_ME(to_xml_string, NULL, ZEND_ACC_PUBLIC) +#ifdef LIBXML_SCHEMAS_ENABLED + SXE_ME(validate_schema_buffer, NULL, ZEND_ACC_PUBLIC) + SXE_ME(validate_schema_file, NULL, ZEND_ACC_PUBLIC) +#endif + SXE_ME(xsearch, NULL, ZEND_ACC_PUBLIC) + SXE_ME(rewind, NULL, ZEND_ACC_PUBLIC) + SXE_ME(hasMore, NULL, ZEND_ACC_PUBLIC) + SXE_ME(current, NULL, ZEND_ACC_PUBLIC) + SXE_ME(key, NULL, ZEND_ACC_PUBLIC) + SXE_ME(next, NULL, ZEND_ACC_PUBLIC) + SXE_ME(hasChildren, NULL, ZEND_ACC_PUBLIC) + SXE_ME(getChildren, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + /* {{{ PHP_MINIT_FUNCTION(simplexml) */ PHP_MINIT_FUNCTION(simplexml) { zend_class_entry sxe; - INIT_CLASS_ENTRY(sxe, "simplexml_element", NULL); + INIT_CLASS_ENTRY(sxe, "simplexml_element", sxe_functions); sxe.create_object = sxe_object_new; sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC); +#if HAVE_SPL + zend_class_implements(sxe_class_entry TSRMLS_CC, 1, spl_ce_RecursiveIterator); +#endif sxe_class_entry->get_iterator = php_sxe_get_iterator; + sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method; + sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry; + sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name; php_libxml_initialize(); diff --git a/ext/simplexml/tests/006.phpt b/ext/simplexml/tests/006.phpt index ac7c77e91c..d17f0429c2 100755 --- a/ext/simplexml/tests/006.phpt +++ b/ext/simplexml/tests/006.phpt @@ -12,30 +12,45 @@ foreach($sxe as $name => $data) { var_dump(trim($data)); } +echo "===CLONE===\n"; + foreach($sxe->__clone() as $name => $data) { var_dump($name); var_dump(trim($data)); } -foreach($sxe->elem1 as $name => $data) { +echo "===ELEMENT===\n"; + +foreach($sxe->elem11 as $name => $data) { var_dump($name); var_dump(trim($data)); } -echo "===Done===\n"; +echo "===COMMENT===\n"; + +foreach($sxe->elem1 as $name => $data) { + var_dump($name); + var_dump(trim($data)); +} ?> +===DONE=== --EXPECT-- string(5) "elem1" string(10) "Bla bla 1." string(6) "elem11" string(10) "Bla bla 2." +===CLONE=== string(5) "elem1" string(10) "Bla bla 1." string(6) "elem11" string(10) "Bla bla 2." +===ELEMENT=== +string(7) "elem111" +string(7) "Foo Bar" +===COMMENT=== string(7) "comment" string(0) "" string(5) "elem2" string(28) "Here we have some text data." -===Done=== +===DONE=== diff --git a/ext/simplexml/tests/006.xml b/ext/simplexml/tests/006.xml index d8d93debde..d518d85e1e 100755 --- a/ext/simplexml/tests/006.xml +++ b/ext/simplexml/tests/006.xml @@ -20,5 +20,8 @@ </elem1> <elem11 attr2='second'> Bla bla 2. + <elem111> + Foo Bar + </elem111> </elem11> </sxe>
\ No newline at end of file |