From 3f07e4364cae8499626d5db4a42cb2d4f6aa6af7 Mon Sep 17 00:00:00 2001 From: Christian Stocker Date: Fri, 28 Nov 2003 22:08:16 +0000 Subject: [PATCH] @- Added possibility to call php functions as XSLT-functions (chregu) - Added possibility to call php functions as XSLT-functions eg: Namespace is http://php.net/functions --- ext/xsl/php_xsl.c | 142 +++++++++++++++++++++++++++++++++++++ ext/xsl/php_xsl.h | 3 + ext/xsl/tests/xslt011.phpt | 29 ++++++++ ext/xsl/tests/xslt011.xml | 1 + ext/xsl/tests/xslt011.xsl | 12 ++++ 5 files changed, 187 insertions(+) create mode 100644 ext/xsl/tests/xslt011.phpt create mode 100644 ext/xsl/tests/xslt011.xml create mode 100644 ext/xsl/tests/xslt011.xsl diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c index 534ff41cad..1661a5930f 100644 --- a/ext/xsl/php_xsl.c +++ b/ext/xsl/php_xsl.c @@ -27,6 +27,9 @@ #include "ext/standard/info.h" #include "php_xsl.h" +static void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs); +static void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs); + /* If you declare any globals in php_xsl.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(xsl) */ @@ -136,11 +139,150 @@ PHP_MINIT_FUNCTION(xsl) #if HAVE_XSL_EXSLT exsltRegisterAll(); #endif + xsltRegisterExtModuleFunction ((const xmlChar *) "functionString", + (const xmlChar *) "http://php.net/xsl", + xsl_ext_function_string_php); + xsltRegisterExtModuleFunction ((const xmlChar *) "function", + (const xmlChar *) "http://php.net/xsl", + xsl_ext_function_object_php); return SUCCESS; } /* }}} */ + +static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) +{ + xsltTransformContextPtr tctxt; + zval **args; + zval *retval; + int result, i, ret; + zend_fcall_info fci; + zval handler; + xmlXPathObjectPtr obj; + char *str; + + TSRMLS_FETCH(); + + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltExtFunctionTest: failed to get the transformation context\n"); + return; + } + + args = safe_emalloc(sizeof(zval **), nargs - 1, 0); + for (i = 0; i < nargs - 1; i++) { + obj = valuePop(ctxt); + MAKE_STD_ZVAL(args[i]); + switch (obj->type) { + case XPATH_STRING: + ZVAL_STRING(args[i], obj->stringval, 1); + break; + case XPATH_BOOLEAN: + ZVAL_BOOL(args[i], obj->boolval); + break; + case XPATH_NUMBER: + ZVAL_DOUBLE(args[i], obj->floatval); + break; + case XPATH_NODESET: + if (type == 1) { + str = xmlXPathCastToString(obj); + ZVAL_STRING(args[i], str, 1); + xmlFree(str); + } else if (type == 2) { + int j; + dom_object *intern; + array_init(args[i]); + if (obj->nodesetval->nodeNr > 0) { + intern = (dom_object *) php_dom_object_get_data((void *) obj->nodesetval->nodeTab[0]->doc); + for (j = 0; j < obj->nodesetval->nodeNr; j++) { + xmlNodePtr node = obj->nodesetval->nodeTab[j]; + zval *child; + + MAKE_STD_ZVAL(child); + /* not sure, if we need this... it's copied from xpath.c */ + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr curns; + xmlNodePtr nsparent; + + nsparent = node->_private; + curns = xmlNewNs(NULL, node->name, NULL); + if (node->children) { + curns->prefix = xmlStrdup((char *) node->children); + } + if (node->children) { + node = xmlNewDocNode(node->doc, NULL, (char *) node->children, node->name); + } else { + node = xmlNewDocNode(node->doc, NULL, "xmlns", node->name); + } + node->type = XML_NAMESPACE_DECL; + node->parent = nsparent; + node->ns = curns; + } + child = php_dom_create_object(node, &ret, NULL, child, intern TSRMLS_CC); + add_next_index_zval(args[i], child); + } + } + } + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "php:function object type %d is not supported yet", obj->type); + ZVAL_STRING(args[i], "", 0); + } + xmlXPathFreeObject(obj); + } + + fci.size = sizeof(fci); + fci.function_table = EG(function_table); + + obj = valuePop(ctxt); + INIT_PZVAL(&handler); + ZVAL_STRING(&handler, obj->stringval, 1); + xmlXPathFreeObject(obj); + + fci.function_name = &handler; + fci.symbol_table = NULL; + fci.object_pp = NULL; + fci.retval_ptr_ptr = &retval; + fci.param_count = nargs - 1; + fci.params = &args; + fci.no_separation = 0; + /*fci.function_handler_cache = &function_ptr;*/ + + result = zend_call_function(&fci, NULL TSRMLS_CC); + if (result == FAILURE) { + if (Z_TYPE(handler) == IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", Z_STRVAL_P(&handler)); + } + } else { + if (retval->type == IS_BOOL) { + valuePush(ctxt, xmlXPathNewBoolean(retval->value.lval)); + } else { + convert_to_string_ex(&retval); + valuePush(ctxt, xmlXPathNewString( Z_STRVAL_P(retval))); + } + zval_ptr_dtor(&retval); + } + zval_dtor(&handler); + for (i = 0; i < nargs - 1; i++) { + zval_ptr_dtor(&args[i]); + } + efree(args); +} + +static void +xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) +{ + xsl_ext_function_php(ctxt, nargs, 1); +} + +static void +xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) +{ + xsl_ext_function_php(ctxt, nargs, 2); +} + /* {{{ xsl_object_get_data */ zval *xsl_object_get_data(void *obj) { diff --git a/ext/xsl/php_xsl.h b/ext/xsl/php_xsl.h index f0ce76955e..cdcea90f42 100644 --- a/ext/xsl/php_xsl.h +++ b/ext/xsl/php_xsl.h @@ -46,6 +46,9 @@ extern zend_module_entry xsl_module_entry; #include "../dom/xml_common.h" #include "xsl_fe.h" +#include +#include + typedef struct _xsl_object { zend_object std; void *ptr; diff --git a/ext/xsl/tests/xslt011.phpt b/ext/xsl/tests/xslt011.phpt new file mode 100644 index 0000000000..a9b9f5767c --- /dev/null +++ b/ext/xsl/tests/xslt011.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test 11: php:function Support +--SKIPIF-- + +--FILE-- +load(dirname(__FILE__)."/xslt011.xsl"); + $proc = new xsltprocessor; + $xsl = $proc->importStylesheet($dom); + + $xml = new DomDocument(); + $xml->load(dirname(__FILE__)."/xslt011.xml"); + + print $proc->transformToXml($xml); + function foobar($id ) { + if (is_array($id)) { + return $id[0]->value; + } else { + return $id; + } + } +--EXPECT-- +Test 11: php:function Support + +foobar +foobar diff --git a/ext/xsl/tests/xslt011.xml b/ext/xsl/tests/xslt011.xml new file mode 100644 index 0000000000..134efd02c0 --- /dev/null +++ b/ext/xsl/tests/xslt011.xml @@ -0,0 +1 @@ + diff --git a/ext/xsl/tests/xslt011.xsl b/ext/xsl/tests/xslt011.xsl new file mode 100644 index 0000000000..f6da07b266 --- /dev/null +++ b/ext/xsl/tests/xslt011.xsl @@ -0,0 +1,12 @@ + + + + + + + + + -- 2.40.0