]> granicus.if.org Git - php/commitdiff
@- Added possibility to call php functions as XSLT-functions (chregu)
authorChristian Stocker <chregu@php.net>
Fri, 28 Nov 2003 22:08:16 +0000 (22:08 +0000)
committerChristian Stocker <chregu@php.net>
Fri, 28 Nov 2003 22:08:16 +0000 (22:08 +0000)
- Added possibility to call php functions as XSLT-functions
  eg: <xsl:value-of select="php:function('date','r')"/>
  Namespace is http://php.net/functions

ext/xsl/php_xsl.c
ext/xsl/php_xsl.h
ext/xsl/tests/xslt011.phpt [new file with mode: 0644]
ext/xsl/tests/xslt011.xml [new file with mode: 0644]
ext/xsl/tests/xslt011.xsl [new file with mode: 0644]

index 534ff41cad04d8409b9e2b61de26eca5c4732bae..1661a5930f1b3dba568b8f33cf2169ba2b4e87ea 100644 (file)
@@ -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)
 {
index f0ce76955eed53ac9a3d1eea9ed087708e4c4951..cdcea90f423d67ef291d1055d012b1b194ee12b7 100644 (file)
@@ -46,6 +46,9 @@ extern zend_module_entry xsl_module_entry;
 #include "../dom/xml_common.h"
 #include "xsl_fe.h"
 
+#include <libxslt/extensions.h>
+#include <libxml/xpathInternals.h>
+
 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 (file)
index 0000000..a9b9f57
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+Test 11: php:function Support
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+print "Test 11: php:function Support\n";
+
+$dom = new domDocument();
+  $dom->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
+<?xml version="1.0"?>
+foobar
+foobar
diff --git a/ext/xsl/tests/xslt011.xml b/ext/xsl/tests/xslt011.xml
new file mode 100644 (file)
index 0000000..134efd0
--- /dev/null
@@ -0,0 +1 @@
+<doc id="foobar"></doc>
diff --git a/ext/xsl/tests/xslt011.xsl b/ext/xsl/tests/xslt011.xsl
new file mode 100644 (file)
index 0000000..f6da07b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+               xmlns:php="http://php.net/xsl"
+               xsl:extension-element-prefixes="php"
+                version='1.0'>
+<xsl:template match="/">
+<xsl:value-of select="php:functionString('foobar', /doc/@id)"/>
+<xsl:text>
+</xsl:text>
+<xsl:value-of select="php:function('foobar', /doc/@id)"/>
+</xsl:template>
+</xsl:stylesheet>