From e8a87e5430dadb4b049d0d0ea0c849fd75c5e0be Mon Sep 17 00:00:00 2001 From: Rob Richards Date: Thu, 24 Jul 2003 13:18:40 +0000 Subject: [PATCH] initial xpath implementation make dom_object generic --- ext/dom/config.m4 | 3 +- ext/dom/dom.dsp | 4 + ext/dom/dom_ce.h | 3 + ext/dom/dom_fe.h | 7 ++ ext/dom/dom_properties.h | 5 ++ ext/dom/element.c | 4 +- ext/dom/php_dom.c | 110 +++++++++++++++++++++----- ext/dom/php_dom.h | 5 +- ext/dom/xml_common.h | 2 +- ext/dom/xpath.c | 167 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 285 insertions(+), 25 deletions(-) create mode 100644 ext/dom/xpath.c diff --git a/ext/dom/config.m4 b/ext/dom/config.m4 index a3a5b159c2..489416e97a 100644 --- a/ext/dom/config.m4 +++ b/ext/dom/config.m4 @@ -21,7 +21,8 @@ if test "$PHP_DOM" != "no"; then element.c node.c string_extend.c characterdata.c \ documenttype.c domimplementationlist.c entity.c \ nodelist.c text.c comment.c domconfiguration.c \ - domimplementationsource.c entityreference.c notation.c \ + domimplementationsource.c entityreference.c \ + notation.c xpath.c \ typeinfo.c domerror.c domlocator.c namednodemap.c userdatahandler.c], $ext_shared) PHP_SUBST(DOM_SHARED_LIBADD) diff --git a/ext/dom/dom.dsp b/ext/dom/dom.dsp index d1293e5d1a..758c5c4663 100644 --- a/ext/dom/dom.dsp +++ b/ext/dom/dom.dsp @@ -213,6 +213,10 @@ SOURCE=.\typeinfo.c SOURCE=.\userdatahandler.c # End Source File +# Begin Source File + +SOURCE=.\xpath.c +# End Source File # End Group # Begin Group "Header Files" diff --git a/ext/dom/dom_ce.h b/ext/dom/dom_ce.h index b210507b86..4dcca6ce7f 100644 --- a/ext/dom/dom_ce.h +++ b/ext/dom/dom_ce.h @@ -50,5 +50,8 @@ zend_class_entry *dom_entity_class_entry; zend_class_entry *dom_entityreference_class_entry; zend_class_entry *dom_processinginstruction_class_entry; zend_class_entry *dom_string_extend_class_entry; +#if defined(LIBXML_XPATH_ENABLED) +zend_class_entry *dom_xpath_class_entry; +#endif #endif /* DOM_CE_H */ diff --git a/ext/dom/dom_fe.h b/ext/dom/dom_fe.h index 45d05cce28..b540d3bab7 100644 --- a/ext/dom/dom_fe.h +++ b/ext/dom/dom_fe.h @@ -50,6 +50,7 @@ extern zend_function_entry php_dom_entity_class_functions[]; extern zend_function_entry php_dom_entityreference_class_functions[]; extern zend_function_entry php_dom_processinginstruction_class_functions[]; extern zend_function_entry php_dom_string_extend_class_functions[]; +extern zend_function_entry php_dom_xpath_class_functions[]; /* domexception errors */ typedef enum { @@ -234,4 +235,10 @@ PHP_FUNCTION(dom_processinginstruction_processinginstruction); PHP_FUNCTION(dom_string_extend_find_offset16); PHP_FUNCTION(dom_string_extend_find_offset32); +#if defined(LIBXML_XPATH_ENABLED) +/* xpath methods */ +PHP_FUNCTION(dom_xpath_xpath); +PHP_FUNCTION(dom_xpath_query); +#endif + #endif /* DOM_FE_H */ diff --git a/ext/dom/dom_properties.h b/ext/dom/dom_properties.h index 8bbc1fda04..b61f8e72a4 100644 --- a/ext/dom/dom_properties.h +++ b/ext/dom/dom_properties.h @@ -142,4 +142,9 @@ int dom_text_whole_text_read(dom_object *obj, zval **retval TSRMLS_DC); int dom_typeinfo_type_name_read(dom_object *obj, zval **retval TSRMLS_DC); int dom_typeinfo_type_namespace_read(dom_object *obj, zval **retval TSRMLS_DC); +#if defined(LIBXML_XPATH_ENABLED) +/* xpath properties */ +int dom_xpath_document_read(dom_object *obj, zval **retval TSRMLS_DC); +#endif + #endif /* DOM_PROPERTIERS_H */ diff --git a/ext/dom/element.c b/ext/dom/element.c index 7f67f66cac..1c75f6982d 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -311,7 +311,7 @@ PHP_FUNCTION(dom_element_set_attribute_node) if ((oldobj = dom_object_get_data((xmlNodePtr) existattrp)) == NULL) { xmlUnlinkNode((xmlNodePtr) existattrp); } else { - if (oldobj->ptr->node == (xmlNodePtr) attrp) { + if (((node_ptr *)oldobj->ptr)->node == (xmlNodePtr) attrp) { RETURN_NULL(); } xmlUnlinkNode((xmlNodePtr) existattrp); @@ -674,7 +674,7 @@ PHP_FUNCTION(dom_element_set_attribute_node_ns) if ((oldobj = dom_object_get_data((xmlNodePtr) existattrp)) == NULL) { xmlUnlinkNode((xmlNodePtr) existattrp); } else { - if (oldobj->ptr->node == (xmlNodePtr) attrp) { + if (((node_ptr *)oldobj->ptr)->node == (xmlNodePtr) attrp) { RETURN_NULL(); } xmlUnlinkNode((xmlNodePtr) existattrp); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index a7003027c6..9a141fe194 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -59,7 +59,9 @@ static HashTable dom_documenttype_prop_handlers; static HashTable dom_notation_prop_handlers; static HashTable dom_entity_prop_handlers; static HashTable dom_processinginstruction_prop_handlers; - +#if defined(LIBXML_XPATH_ENABLED) +static HashTable dom_xpath_prop_handlers; +#endif typedef int (*dom_read_t)(dom_object *obj, zval **retval TSRMLS_DC); typedef int (*dom_write_t)(dom_object *obj, zval *newval TSRMLS_DC); @@ -152,12 +154,14 @@ int decrement_document_reference(dom_object *object TSRMLS_DC) { /* {{{ int decrement_node_ptr(dom_object *object) */ int decrement_node_ptr(dom_object *object TSRMLS_DC) { int ret_refcount = -1; + node_ptr *obj_node; if (object != NULL && object->ptr != NULL) { - ret_refcount = --object->ptr->refcount; + obj_node = (node_ptr *) object->ptr; + ret_refcount = --obj_node->refcount; if (ret_refcount == 0) { - if (object->ptr->node != NULL) { - object->ptr->node->_private = NULL; + if (obj_node->node != NULL) { + obj_node->node->_private = NULL; } efree(object->ptr); } @@ -172,7 +176,7 @@ int decrement_node_ptr(dom_object *object TSRMLS_DC) { xmlNodePtr dom_object_get_node(dom_object *obj) { if (obj->ptr != NULL) { - return obj->ptr->node; + return ((node_ptr *)obj->ptr)->node; } else { return NULL; } @@ -215,17 +219,21 @@ static void php_dom_clear_object(dom_object *object TSRMLS_DC) /* {{{ void php_dom_set_object(dom_object *object, xmlNodePtr obj TSRMLS_DC) */ void php_dom_set_object(dom_object *object, xmlNodePtr obj TSRMLS_DC) { + node_ptr *obj_node; + if (obj->_private == NULL) { object->ptr = emalloc(sizeof(node_ptr)); - object->ptr->node = obj; - object->ptr->refcount = 1; - object->ptr->_private = object; + obj_node = (node_ptr *)object->ptr; + obj_node->node = obj; + obj_node->refcount = 1; + obj_node->_private = object; dom_object_set_data(obj, object TSRMLS_CC); } else if (object->ptr == NULL) { - object->ptr = obj->_private; - object->ptr->refcount++; - if (object->ptr->_private == NULL) { - object->ptr->_private = object; + (node_ptr *)object->ptr = obj->_private; + obj_node = (node_ptr *)object->ptr; + obj_node->refcount++; + if (obj_node->_private == NULL) { + obj_node->_private = object; } } } @@ -573,6 +581,16 @@ PHP_MINIT_FUNCTION(dom) REGISTER_DOM_CLASS(ce, "domstring_extend", NULL, php_dom_string_extend_class_functions, dom_string_extend_class_entry); +#if defined(LIBXML_XPATH_ENABLED) + INIT_CLASS_ENTRY(ce, "domxpath", php_dom_xpath_class_functions); + ce.create_object = dom_xpath_objects_new; + dom_xpath_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); + + zend_hash_init(&dom_xpath_prop_handlers, 0, NULL, NULL, 1); + dom_register_prop_handler(&dom_xpath_prop_handlers, "document", dom_xpath_document_read, NULL TSRMLS_CC); + zend_hash_add(&classes, ce.name, ce.name_length + 1, &dom_xpath_prop_handlers, sizeof(dom_xpath_prop_handlers), NULL); +#endif + REGISTER_LONG_CONSTANT("XML_ELEMENT_NODE", XML_ELEMENT_NODE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NODE", XML_ATTRIBUTE_NODE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("XML_TEXT_NODE", XML_TEXT_NODE, CONST_CS | CONST_PERSISTENT); @@ -653,6 +671,9 @@ PHP_MSHUTDOWN_FUNCTION(dom) zend_hash_destroy(&dom_notation_prop_handlers); zend_hash_destroy(&dom_entity_prop_handlers); zend_hash_destroy(&dom_processinginstruction_prop_handlers); +#if defined(LIBXML_XPATH_ENABLED) + zend_hash_destroy(&dom_xpath_prop_handlers); +#endif zend_hash_destroy(&classes); /* If you want do find memleaks in this module, compile libxml2 with --with-mem-debug and @@ -811,6 +832,26 @@ void dom_objects_clone(void *object, void **object_clone TSRMLS_DC) } /* }}} */ +#if defined(LIBXML_XPATH_ENABLED) +/* {{{ dom_xpath_objects_dtor */ +void dom_xpath_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC) +{ + dom_object *intern = (dom_object *)object; + + zend_hash_destroy(intern->std.properties); + FREE_HASHTABLE(intern->std.properties); + + if (intern->ptr != NULL) { + xmlXPathFreeContext((xmlXPathContextPtr) intern->ptr); + decrement_document_reference((dom_object *) intern TSRMLS_CC); + intern->ptr = NULL; + } + + efree(object); +} +/* }}} */ +#endif + /* {{{ dom_objects_dtor */ void dom_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC) { @@ -820,8 +861,8 @@ void dom_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC) zend_hash_destroy(intern->std.properties); FREE_HASHTABLE(intern->std.properties); - if (intern->ptr != NULL && intern->ptr->node != NULL) { - if (((xmlNodePtr) intern->ptr->node)->type != XML_DOCUMENT_NODE && ((xmlNodePtr) intern->ptr->node)->type != XML_HTML_DOCUMENT_NODE) { + if (intern->ptr != NULL && ((node_ptr *)intern->ptr)->node != NULL) { + if (((xmlNodePtr) ((node_ptr *)intern->ptr)->node)->type != XML_DOCUMENT_NODE && ((xmlNodePtr) ((node_ptr *)intern->ptr)->node)->type != XML_HTML_DOCUMENT_NODE) { node_free_resource(dom_object_get_node(intern) TSRMLS_CC); } else { decrement_node_ptr(intern TSRMLS_CC); @@ -834,13 +875,12 @@ void dom_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC) } /* }}} */ -/* {{{ dom_objects_new */ -zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC) +/* {{{ dom_objects_set_class */ +static dom_object* dom_objects_set_class(zend_class_entry *class_type TSRMLS_DC) { - zend_object_value retval; - dom_object *intern; zend_class_entry *base_class; zval *tmp; + dom_object *intern; intern = emalloc(sizeof(dom_object)); intern->std.ce = class_type; @@ -849,7 +889,7 @@ zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC) intern->ptr = NULL; intern->prop_handler = NULL; intern->document = NULL; - + base_class = class_type; while(base_class->type != ZEND_INTERNAL_CLASS && base_class->parent != NULL) { base_class = base_class->parent; @@ -861,6 +901,18 @@ zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC) zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + return intern; +} +/* }}} */ + +/* {{{ dom_objects_new */ +zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value retval; + dom_object *intern; + + intern = dom_objects_set_class(class_type TSRMLS_CC); + retval.handle = zend_objects_store_put(intern, dom_objects_dtor, dom_objects_clone TSRMLS_CC); intern->handle = retval.handle; retval.handlers = &dom_object_handlers; @@ -869,7 +921,25 @@ zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC) } /* }}} */ -/* {{{ php_domobject_new */ +#if defined(LIBXML_XPATH_ENABLED) +/* {{{ zend_object_value dom_xpath_objects_new(zend_class_entry *class_type TSRMLS_DC) */ +zend_object_value dom_xpath_objects_new(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value retval; + dom_object *intern; + + intern = dom_objects_set_class(class_type TSRMLS_CC); + + retval.handle = zend_objects_store_put(intern, dom_xpath_objects_dtor, dom_objects_clone TSRMLS_CC); + intern->handle = retval.handle; + retval.handlers = &dom_object_handlers; + + return retval; +} +/* }}} */ +#endif + +/* {{{ php_dom_create_object */ zval *php_dom_create_object(xmlNodePtr obj, int *found, zval *wrapper_in, zval *return_value, dom_object *domobj TSRMLS_DC) { zval *wrapper; diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index d3a5eb0bfc..4f5d947594 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -68,6 +68,9 @@ void php_dom_set_object(dom_object *object, xmlNodePtr obj TSRMLS_DC); dom_object *dom_object_get_data(xmlNodePtr obj); xmlNodePtr dom_object_get_node(dom_object *obj); zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC); +#if defined(LIBXML_XPATH_ENABLED) +zend_object_value dom_xpath_objects_new(zend_class_entry *class_type TSRMLS_DC); +#endif void php_dom_throw_error(int error_code, zval **retval TSRMLS_DC); void node_free_resource(xmlNodePtr node TSRMLS_DC); void node_list_unlink(xmlNodePtr node TSRMLS_DC); @@ -93,7 +96,7 @@ entry = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC); #define DOM_GET_OBJ(__ptr, __id, __prtype, __intern) { \ __intern = (dom_object *)zend_object_store_get_object(__id TSRMLS_CC); \ - if (__intern->ptr == NULL || !(__ptr = (__prtype)__intern->ptr->node)) { \ + if (__intern->ptr == NULL || !(__ptr = (__prtype)((node_ptr *)__intern->ptr)->node)) { \ php_error(E_WARNING, "Couldn't fetch %s", __intern->std.ce->name);\ RETURN_NULL();\ } \ diff --git a/ext/dom/xml_common.h b/ext/dom/xml_common.h index 304635f85c..629538232b 100644 --- a/ext/dom/xml_common.h +++ b/ext/dom/xml_common.h @@ -41,7 +41,7 @@ typedef struct _node_object { typedef struct _dom_object { zend_object std; - node_ptr *ptr; + void *ptr; dom_ref_obj *document; HashTable *prop_handler; zend_object_handle handle; diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c new file mode 100644 index 0000000000..2302733260 --- /dev/null +++ b/ext/dom/xpath.c @@ -0,0 +1,167 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Christian Stocker | + | Rob Richards | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_dom.h" + + +/* +* class domxpath +*/ + +#if defined(LIBXML_XPATH_ENABLED) + +zend_function_entry php_dom_xpath_class_functions[] = { + PHP_FALIAS(domxpath, dom_xpath_xpath, NULL) + PHP_FALIAS(query, dom_xpath_query, NULL) + {NULL, NULL, NULL} +}; + +/* {{{ proto domxpath dom_xpath_xpath(domDocument doc); */ +PHP_FUNCTION(dom_xpath_xpath) +{ + zval *id, *doc; + xmlDocPtr docp = NULL; + dom_object *docobj, *intern; + xmlXPathContextPtr ctx, oldctx; + + id = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &doc) == FAILURE) { + return; + } + + DOM_GET_OBJ(docp, doc, xmlDocPtr, docobj); + + ctx = xmlXPathNewContext(docp); + if (ctx == NULL) { + RETURN_FALSE; + } + + intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC); + if (intern != NULL) { + oldctx = (xmlXPathContextPtr)intern->ptr; + if (oldctx != NULL) { + decrement_document_reference(intern TSRMLS_CC); + xmlXPathFreeContext(oldctx); + } + intern->ptr = ctx; + intern->document = docobj->document; + increment_document_reference(intern, docp TSRMLS_CC); + } +} +/* }}} end dom_xpath_xpath */ + +/* {{{ proto domdocument document document */ +int dom_xpath_document_read(dom_object *obj, zval **retval TSRMLS_DC) +{ + xmlDoc *docp = NULL; + xmlXPathContextPtr ctx; + int ret; + + ctx = (xmlXPathContextPtr) obj->ptr; + + if (ctx) { + docp = (xmlDocPtr) ctx->doc; + } else { + printf("NONE"); + } + + ALLOC_ZVAL(*retval); + if (NULL == (*retval = php_dom_create_object((xmlNodePtr) docp, &ret, NULL, *retval, obj TSRMLS_CC))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create required DOM object"); + return FAILURE; + } + return SUCCESS; +} + +/* {{{ proto domnodelist dom_xpath_query(string expr [,domNode context]); */ +PHP_FUNCTION(dom_xpath_query) +{ + zval *id, *context = NULL; + xmlXPathContextPtr ctxp; + xmlNodePtr nodep = NULL; + xmlXPathObjectPtr xpathobjp; + int expr_len, ret; + dom_object *intern, *nodeobj; + char *expr; + + DOM_GET_THIS(id); + + intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC); + + ctxp = (xmlXPathContextPtr) intern->ptr; + if (ctxp == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid XPath Context"); + RETURN_FALSE; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|o", &expr, &expr_len, &context) == FAILURE) { + return; + } + + if (context != NULL) { + DOM_GET_OBJ(nodep, context, xmlNodePtr, nodeobj); + } + + ctxp->node = nodep; + + xpathobjp = xmlXPathEvalExpression(expr, ctxp); + ctxp->node = NULL; + + if (!xpathobjp) { + RETURN_FALSE; + } + + if (xpathobjp->type == XPATH_NODESET) { + int i; + xmlNodeSetPtr nodesetp; + + if (NULL == (nodesetp = xpathobjp->nodesetval)) { + xmlXPathFreeObject (xpathobjp); + RETURN_FALSE; + } + + array_init(return_value); + + for (i = 0; i < nodesetp->nodeNr; i++) { + xmlNodePtr node = nodesetp->nodeTab[i]; + zval *child; + MAKE_STD_ZVAL(child); + + child = php_dom_create_object(node, &ret, NULL, child, intern TSRMLS_CC); + add_next_index_zval(return_value, child); + } + } else { + printf("Type: %d", xpathobjp->type); + } + + xmlXPathFreeObject(xpathobjp); +} +/* }}} end dom_xpath_query */ + +#endif /* LIBXML_XPATH_ENABLED */ + +/* }}} */ -- 2.40.0