|
From: Petr P. <pa...@us...> - 2003-03-14 16:23:55
|
Update of /cvsroot/perl-xml/XML-LibXML-XPathContext
In directory sc8-pr-cvs1:/tmp/cvs-serv21709
Modified Files:
XPathContext.xs XPathContext.pm
Log Message:
added extension functions support
Index: XPathContext.xs
===================================================================
RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/XPathContext.xs,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- XPathContext.xs 14 Mar 2003 16:12:39 -0000 1.2
+++ XPathContext.xs 14 Mar 2003 16:23:50 -0000 1.3
@@ -63,122 +63,338 @@
/* ****************************************************************
* Variable Lookup
* **************************************************************** */
-xmlXPathObjectPtr
+/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT */
+static xmlXPathObjectPtr
LibXML_generic_variable_lookup(void* varLookupData,
const xmlChar *name,
const xmlChar *ns_uri)
{
- xmlXPathObjectPtr ret;
- SV * lookup_func;
- SV * lookup_data;
- I32 count;
- STRLEN n_a;
- SV * perl_result;
- AV * array_result;
- xmlNodePtr tmp_node, tmp_node1;
- dSP;
- char * tmp_string;
- double tmp_double;
- int tmp_int;
- SV * data = (SV *) varLookupData;
-
- if (varLookupData == NULL ||
- SvTYPE(SvRV(data)) != SVt_PVAV) {
- croak("LibXML: lost data structure for variable lookup.\n");
- }
+ xmlXPathObjectPtr ret;
+ SV * lookup_func;
+ SV * lookup_data;
+ I32 count;
+ STRLEN n_a;
+ SV * perl_result;
+ AV * array_result;
+ xmlNodePtr tmp_node, tmp_node1;
+ dSP;
+ char * tmp_string;
+ double tmp_double;
+ int tmp_int;
+ SV * data;
- lookup_func = *(av_fetch((AV *) SvRV(data),0,0 ));
- lookup_data = *(av_fetch((AV *) SvRV(data),1,0 ));
+ data = (SV *) varLookupData;
+ if (varLookupData == NULL || !SvROK(data) ||
+ SvTYPE(SvRV(data)) != SVt_PVAV) {
+ croak("XPathContext: lost variable lookup data structure!\n");
+ }
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
+ lookup_func = *(av_fetch((AV *) SvRV(data),0,0 ));
+ lookup_data = *(av_fetch((AV *) SvRV(data),1,0 ));
- XPUSHs(lookup_data);
- XPUSHs(sv_2mortal(C2Sv(name,NULL)));
- XPUSHs(sv_2mortal(C2Sv(ns_uri,NULL)));
- PUTBACK ;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
- count = perl_call_sv(lookup_func, G_SCALAR|G_EVAL);
+ XPUSHs(lookup_data);
+ XPUSHs(sv_2mortal(C2Sv(name,NULL)));
+ XPUSHs(sv_2mortal(C2Sv(ns_uri,NULL)));
+ PUTBACK ;
- SPAGAIN;
- if (SvTRUE(ERRSV)) {
- POPs;
- croak("LibXML: error coming back from variable lookup function. %s\n", SvPV(ERRSV, n_a));
- }
- if (count != 1) croak("LibXML: variable lookup function returned more than one argument!\n");
+ count = perl_call_sv(lookup_func, G_SCALAR|G_EVAL);
- perl_result = POPs;
- if (!SvOK(perl_result)) {
- ret = (xmlXPathObjectPtr)xmlXPathNewCString("");
- goto FINISH;
- }
- /* convert perl result structures to LibXML structures */
- if (sv_isobject(perl_result) &&
- (SvTYPE(SvRV(perl_result)) == SVt_PVMG ||
- SvTYPE(SvRV(perl_result)) == SVt_PVAV))
- {
- if (sv_isa(perl_result, "XML::LibXML::NodeList")) {
- int i = 0;
- int len;
- /* warn("result is a node list\n"); */
- ret = (xmlXPathObjectPtr) xmlXPathNewNodeSet((xmlNodePtr) NULL);
- array_result = (AV*)SvRV(perl_result);
- len = av_len(array_result);
- for( i; i <= len ; i++ ) {
- tmp_node = (xmlNodePtr)PmmSvNode(*(av_fetch(array_result,i,0)));
- xmlXPathNodeSetAdd(ret->nodesetval, tmp_node);
- }
- goto FINISH;
- }
- else if (sv_isa(perl_result, "XML::LibXML::Node") ||
- sv_isa(perl_result, "XML::LibXML::Element") ||
- sv_isa(perl_result, "XML::LibXML::Attr") ||
- sv_isa(perl_result, "XML::LibXML::Text") ||
- sv_isa(perl_result, "XML::LibXML::Comment") ||
- sv_isa(perl_result, "XML::LibXML::Document") ||
- sv_isa(perl_result, "XML::LibXML::PI")) {
- /* warn("result is a node\n"); */
- ret = (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
- tmp_node = (xmlNodePtr)PmmSvNode(perl_result);
- xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
- goto FINISH;
- }
- else if (sv_isa(perl_result, "XML::LibXML::Boolean")) {
- /* warn("result is a boolean\n"); */
- tmp_int = SvIV(SvRV(perl_result));
- ret = (xmlXPathObjectPtr)xmlXPathNewBoolean(tmp_int);
- goto FINISH;
- }
- else if (sv_isa(perl_result, "XML::LibXML::Literal")) {
- /* warn("result is a literal\n"); */
- tmp_string = SvPV(SvRV(perl_result), n_a);
- ret = (xmlXPathObjectPtr)xmlXPathNewCString(tmp_string);
- goto FINISH;
- }
- else if (sv_isa(perl_result, "XML::LibXML::Number")) {
- /* warn("result is a number\n"); */
- tmp_double = SvNV(SvRV(perl_result));
- ret = (xmlXPathObjectPtr)xmlXPathNewFloat(tmp_double);
- goto FINISH;
- }
- } else if (SvNOK(perl_result) || SvIOK(perl_result)) {
- /* warn("result is an unblessed number\n"); */
- ret = (xmlXPathObjectPtr)xmlXPathNewFloat(SvNV(perl_result));
- } else {
- /* warn("result is an unblessed string\n"); */
- ret = (xmlXPathObjectPtr)xmlXPathNewCString(SvPV(perl_result, n_a));
- }
+ SPAGAIN;
+ if (SvTRUE(ERRSV)) {
+ POPs;
+ croak("XPathContext: error coming back from variable lookup function. %s\n", SvPV(ERRSV, n_a));
+ }
+ if (count != 1) croak("XPathContext: variable lookup function returned more than one argument!\n");
+ perl_result = POPs;
+ if (!SvOK(perl_result)) {
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString("");
+ goto FINISH;
+ }
+ /* convert perl result structures to LibXML structures */
+ if (sv_isobject(perl_result) &&
+ (SvTYPE(SvRV(perl_result)) == SVt_PVMG ||
+ SvTYPE(SvRV(perl_result)) == SVt_PVAV))
+ {
+ if (sv_isa(perl_result, "XML::LibXML::NodeList")) {
+ int i = 0;
+ int len;
+ /* warn("result is a node list\n"); */
+ ret = (xmlXPathObjectPtr) xmlXPathNewNodeSet((xmlNodePtr) NULL);
+ array_result = (AV*)SvRV(perl_result);
+ len = av_len(array_result);
+ for( i; i <= len ; i++ ) {
+ tmp_node = (xmlNodePtr)PmmSvNode(*(av_fetch(array_result,i,0)));
+ xmlXPathNodeSetAdd(ret->nodesetval, tmp_node);
+ }
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Node") ||
+ sv_isa(perl_result, "XML::LibXML::Element") ||
+ sv_isa(perl_result, "XML::LibXML::Attr") ||
+ sv_isa(perl_result, "XML::LibXML::Text") ||
+ sv_isa(perl_result, "XML::LibXML::Comment") ||
+ sv_isa(perl_result, "XML::LibXML::Document") ||
+ sv_isa(perl_result, "XML::LibXML::PI")) {
+ /* warn("result is a node\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
+ tmp_node = (xmlNodePtr)PmmSvNode(perl_result);
+ xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Boolean")) {
+ /* warn("result is a boolean\n"); */
+ tmp_int = SvIV(SvRV(perl_result));
+ ret = (xmlXPathObjectPtr)xmlXPathNewBoolean(tmp_int);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Literal")) {
+ /* warn("result is a literal\n"); */
+ tmp_string = SvPV(SvRV(perl_result), n_a);
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString(tmp_string);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Number")) {
+ /* warn("result is a number\n"); */
+ tmp_double = SvNV(SvRV(perl_result));
+ ret = (xmlXPathObjectPtr)xmlXPathNewFloat(tmp_double);
+ goto FINISH;
+ }
+ } else if (SvNOK(perl_result) || SvIOK(perl_result)) {
+ /* warn("result is an unblessed number\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewFloat(SvNV(perl_result));
+ } else {
+ /* warn("result is an unblessed string\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString(SvPV(perl_result, n_a));
+ }
+
-FINISH:
+ FINISH:
- PUTBACK;
- FREETMPS;
- LEAVE;
- return ret;
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ return ret;
}
+/* ****************************************************************
+ * Generic Extension Function
+ * **************************************************************** */
+/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT */
+static void
+LibXML_generic_extension_function(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ xmlXPathObjectPtr obj,ret;
+ xmlNodeSetPtr nodelist = NULL;
+ int count;
+ SV * perl_dispatch;
+ int i;
+ STRLEN len;
+ SV * perl_result;
+ ProxyNodePtr owner = NULL;
+ char * tmp_string;
+ STRLEN n_a;
+ double tmp_double;
+ int tmp_int;
+ AV * array_result;
+ xmlNodePtr tmp_node;
+ SV *key;
+ char *strkey;
+ const char *function, *uri;
+ SV **perl_function;
+ int xslt_tree = 0;
+ dSP;
+ SV * data;
+
+ /* warn("entered LibXML_generic_extension_function for %s\n",ctxt->context->function); */
+ data = (SV *) ctxt->context->funcLookupData;
+ if (ctxt->context->funcLookupData == NULL || !SvROK(data) ||
+ SvTYPE(SvRV(data)) != SVt_PVHV) {
+ croak("XPathContext: lost function lookup data structure!\n");
+ }
+
+ function = ctxt->context->function;
+ uri = ctxt->context->functionURI;
+
+ key = newSVpvn("",0);
+ if (uri && *uri) {
+ sv_catpv(key, "{");
+ sv_catpv(key, (const char*)uri);
+ sv_catpv(key, "}");
+ }
+ sv_catpv(key, (const char*)function);
+ strkey = SvPV(key, len);
+ perl_function =
+ hv_fetch((HV*)SvRV(data), strkey, len, 0);
+ SvREFCNT_dec(key);
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+
+ XPUSHs(*perl_function);
+
+ /* set up call to perl dispatcher function */
+ for (i = 0; i < nargs; i++) {
+ obj = (xmlXPathObjectPtr)valuePop(ctxt);
+ xslt_tree = 0;
+ switch (obj->type) {
+ case XPATH_XSLT_TREE: /* PP: what's this? */
+ warn("%d's argument to %s is XPATH_XSLT_TREE",i,function);
+ xslt_tree = 1; /* PP: these are destroyed (they have boolval=1) */
+ case XPATH_NODESET:
+ nodelist = obj->nodesetval;
+ if ( nodelist ) {
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
+ XPUSHs(sv_2mortal(newSViv(nodelist->nodeNr)));
+ if ( nodelist->nodeNr > 0 ) {
+ int j = 0 ;
+ const char * cls = "XML::LibXML::Node";
+ xmlNodePtr tnode;
+ SV * element;
+
+ len = nodelist->nodeNr;
+ for( j ; j < len; j++){
+ tnode = nodelist->nodeTab[j];
+ if( tnode != NULL && tnode->doc != NULL) {
+ owner = SvPROXYNODE(sv_2mortal(PmmNodeToSv((xmlNodePtr)(tnode->doc), NULL)));
+ }
+ if (tnode->type == XML_NAMESPACE_DECL) {
+ element = sv_newmortal();
+ cls = PmmNodeTypeName( tnode );
+ element = sv_setref_pv( element,
+ (const char *)cls,
+ (void *)xmlCopyNamespace((xmlNsPtr)tnode)
+ );
+ }
+ else {
+ /* need to copy the node as libxml2 will free it */
+ /* PP: I guess its only true for XSLT_TREEs */
+ if (xslt_tree) {
+ xmlNodePtr tnode_cpy = xmlCopyNode(tnode, 1);
+ element = PmmNodeToSv(tnode_cpy, owner);
+ } else {
+ element = PmmNodeToSv(tnode, owner);
+ }
+ }
+ XPUSHs( sv_2mortal(element) );
+ }
+ }
+ } else {
+ /* PP: We can't simply leave out an empty nodelist as Matt does! */
+ /* PP: The number of arguments must match! */
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
+ XPUSHs(sv_2mortal(newSViv(0)));
+ }
+ break;
+ case XPATH_BOOLEAN:
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
+ XPUSHs(sv_2mortal(newSViv(obj->boolval)));
+ break;
+ case XPATH_NUMBER:
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
+ XPUSHs(sv_2mortal(newSVnv(obj->floatval)));
+ break;
+ case XPATH_STRING:
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
+ XPUSHs(sv_2mortal(C2Sv(obj->stringval, 0)));
+ break;
+ default:
+ warn("Unknown XPath return type (%d) in call to {%s}%s - assuming string", obj->type, uri, function);
+ XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
+ XPUSHs(sv_2mortal(C2Sv((char*)xmlXPathCastToString(obj), 0)));
+ }
+ xmlXPathFreeObject(obj);
+ }
+
+ /* call perl dispatcher */
+ PUTBACK;
+
+ perl_dispatch = sv_2mortal(newSVpv("XML::LibXML::XPathContext::perl_dispatcher",0));
+ count = perl_call_sv(perl_dispatch, G_SCALAR|G_EVAL);
+
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ POPs;
+ croak("XPathContext: error coming back from perl-dispatcher in pm file. %s\n", SvPV(ERRSV, n_a));
+ }
+
+ if (count != 1) croak("XPathContext: perl-dispatcher in pm file returned more than one argument!\n");
+
+ perl_result = POPs;
+ if (!SvOK(perl_result)) {
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString("");
+ goto FINISH;
+ }
+
+ /* convert perl result structures to LibXML structures */
+ if (sv_isobject(perl_result) &&
+ (SvTYPE(SvRV(perl_result)) == SVt_PVMG ||
+ SvTYPE(SvRV(perl_result)) == SVt_PVAV))
+ {
+ if (sv_isa(perl_result, "XML::LibXML::NodeList")) {
+ i = 0;
+ /* warn("result is a node list\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
+ array_result = (AV*)SvRV(perl_result);
+ len = av_len(array_result);
+ for( i; i <= len ; i++ ) {
+ tmp_node = (xmlNodePtr)PmmSvNode(*(av_fetch(array_result,i,0)));
+ xmlXPathNodeSetAdd(ret->nodesetval, tmp_node);
+ }
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Node") ||
+ sv_isa(perl_result, "XML::LibXML::Element") ||
+ sv_isa(perl_result, "XML::LibXML::Attr") ||
+ sv_isa(perl_result, "XML::LibXML::Text") ||
+ sv_isa(perl_result, "XML::LibXML::Comment") ||
+ sv_isa(perl_result, "XML::LibXML::Document") ||
+ sv_isa(perl_result, "XML::LibXML::PI")) {
+ /* warn("result is a node\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
+ tmp_node = (xmlNodePtr)PmmSvNode(perl_result);
+ xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Boolean")) {
+ /* warn("result is a boolean\n"); */
+ tmp_int = SvIV(SvRV(perl_result));
+ ret = (xmlXPathObjectPtr)xmlXPathNewBoolean(tmp_int);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Literal")) {
+ /* warn("result is a literal\n"); */
+ tmp_string = SvPV(SvRV(perl_result), len);
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString(tmp_string);
+ goto FINISH;
+ }
+ else if (sv_isa(perl_result, "XML::LibXML::Number")) {
+ /* warn("result is a number\n"); */
+ tmp_double = SvNV(SvRV(perl_result));
+ ret = (xmlXPathObjectPtr)xmlXPathNewFloat(tmp_double);
+ goto FINISH;
+ }
+ } else if (SvNOK(perl_result) || SvIOK(perl_result)) {
+ /* warn("result is an unblessed number\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewFloat(SvNV(perl_result));
+ } else {
+ /* warn("result is an unblessed string\n"); */
+ ret = (xmlXPathObjectPtr)xmlXPathNewCString(SvPV(perl_result, n_a));
+ }
+
+ FINISH:
+
+ valuePush(ctxt, ret);
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+}
MODULE = XML::LibXML::XPathContext PACKAGE = XML::LibXML::XPathContext
@@ -225,15 +441,19 @@
CODE:
xs_warn( "DESTROY XPATH CONTEXT" );
if (ctxt) {
- if (ctxt->namespaces != NULL) {
- xmlFree( ctxt->namespaces );
- }
- if (ctxt->varLookupData != NULL
- && SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) {
- SvREFCNT_dec((SV *)ctxt->varLookupData);
- }
-
- xmlXPathFreeContext(ctxt);
+ if (ctxt->namespaces != NULL) {
+ xmlFree( ctxt->namespaces );
+ }
+ if (ctxt->varLookupData != NULL && SvROK((SV*)ctxt->varLookupData)
+ && SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) {
+ SvREFCNT_dec((SV *)ctxt->varLookupData);
+ }
+ if (ctxt->funcLookupData != NULL && SvROK((SV*)ctxt->funcLookupData)
+ && SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
+ SvREFCNT_dec((SV *)ctxt->funcLookupData);
+ }
+
+ xmlXPathFreeContext(ctxt);
}
void
@@ -261,13 +481,14 @@
INIT:
xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
CODE:
- if (ctxt->varLookupData != NULL
- && SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) {
- RETVAL = *(av_fetch((AV *) SvRV((SV*)ctxt->varLookupData),1,0 ));
- SvREFCNT_inc(RETVAL);
+ if (ctxt->varLookupData != NULL &&
+ SvROK((SV*)(ctxt->varLookupData)) &&
+ SvTYPE(SvRV((SV*)(ctxt->varLookupData))) == SVt_PVAV) {
+ RETVAL = *(av_fetch((AV *) SvRV((SV*)(ctxt->varLookupData)),1,0));
+ SvREFCNT_inc(RETVAL);
} else {
- RETVAL = &PL_sv_undef;
- }
+ RETVAL = &PL_sv_undef;
+ }
OUTPUT:
RETVAL
@@ -281,13 +502,13 @@
SV * lookup_data
PREINIT:
xmlXPathContextPtr ctxt = NULL;
- SV* pfdr;
+ SV* pfdr;
INIT:
ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
if ( ctxt == NULL ) {
croak( "missing xpath context" );
}
- if ( SvTYPE(SvRV(lookup_func)) == SVt_PVCV ) {
+ if ( SvROK(lookup_func) && SvTYPE(SvRV(lookup_func)) == SVt_PVCV ) {
pfdr = newRV_inc((SV*) newAV());
av_push((AV *)SvRV(pfdr), SvREFCNT_inc(lookup_func));
av_push((AV *)SvRV(pfdr), SvREFCNT_inc(lookup_data));
@@ -295,20 +516,72 @@
croak( "1st argument is not a CODE reference" );
}
if (ctxt->varLookupData != NULL) {
- if (SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) {
- SvREFCNT_dec((SV *)ctxt->varLookupData);
- ctxt->varLookupData = NULL;
- ctxt->varLookupFunc = NULL;
- } else {
- croak("can't register: varLookupData slot already occupied\n");
- }
- }
+ if (SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) {
+ SvREFCNT_dec((SV *)ctxt->varLookupData);
+ ctxt->varLookupData = NULL;
+ ctxt->varLookupFunc = NULL;
+ } else {
+ croak("can't register: varLookupData slot already occupied\n");
+ }
+ }
PPCODE:
xmlXPathRegisterVariableLookup(ctxt, LibXML_generic_variable_lookup, pfdr);
- if (ctxt->varLookupData==NULL || ctxt->varLookupData != pfdr) {
- croak( "registrating failed\n" );
+ if (ctxt->varLookupData==NULL || ctxt->varLookupData != pfdr) {
+ croak( "registrating failed\n" );
}
+void
+registerFunctionNS( pxpath_context, name, uri, func)
+ SV * pxpath_context
+ char * name
+ char * uri
+ SV * func
+ PREINIT:
+ xmlXPathContextPtr ctxt = NULL;
+ SV * pfdr;
+ SV * key;
+ STRLEN len;
+ char *strkey;
+
+ INIT:
+ ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
+ if ( ctxt == NULL ) {
+ croak( "missing xpath context" );
+ }
+ if ( SvTYPE(SvRV(func)) == SVt_PVCV ) {
+ if (ctxt->funcLookupData == NULL) {
+ pfdr = newRV_inc((SV*) newHV());
+ ctxt->funcLookupData = pfdr;
+ } else {
+ if (SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
+ /* good, it's a HV */
+ pfdr = (SV *)ctxt->funcLookupData;
+ } else {
+ croak ( "can't register: funcLookupData structure occupied\n" );
+ }
+ }
+ key = newSVpvn("",0);
+ if (uri && *uri) {
+ sv_catpv(key, "{");
+ sv_catpv(key, (const char*)uri);
+ sv_catpv(key, "}");
+ }
+ sv_catpv(key, (const char*)name);
+ strkey = SvPV(key, len);
+ /* warn("Trying to store function '%s' in %d\n", strkey, pfdr); */
+ hv_store((HV *)SvRV(pfdr),strkey, len, SvREFCNT_inc(func), 0);
+ SvREFCNT_dec(key);
+ } else {
+ croak( "function is not a CODE reference\n" );
+ }
+ PPCODE:
+ if (uri && *uri) {
+ /* warn("Registering function with NS '%s' (uri: %s)\n", name, uri); */
+ xmlXPathRegisterFuncNS(ctxt, name, uri, LibXML_generic_extension_function);
+ } else {
+ /* warn("Registering function '%s'\n", name); */
+ xmlXPathRegisterFunc(ctxt, name, LibXML_generic_extension_function);
+ }
void
_findnodes( pxpath_context, perl_xpath )
Index: XPathContext.pm
===================================================================
RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/XPathContext.pm,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- XPathContext.pm 14 Mar 2003 16:12:40 -0000 1.2
+++ XPathContext.pm 14 Mar 2003 16:23:51 -0000 1.3
@@ -3,7 +3,7 @@
package XML::LibXML::XPathContext;
use strict;
-use vars qw($VERSION @ISA);
+use vars qw($VERSION @ISA $USE_LIBXML_DATA_TYPES);
use XML::LibXML::NodeList;
@@ -14,6 +14,10 @@
bootstrap XML::LibXML::XPathContext $VERSION;
+# should LibXML XPath data types be used for simple objects
+# when passing parameters to extension functions (default: no)
+$USE_LIBXML_DATA_TYPES = 0;
+
sub findnodes {
my ($self, $xpath) = @_;
my @nodes = $self->_findnodes($xpath);
@@ -45,6 +49,43 @@
}
return undef;
}
+
+sub registerFunction {
+ my ($self, $name, $sub)=@_;
+ $self->registerFunctionNS($name,undef,$sub);
+ return;
+}
+
+# extension function perl dispatcher
+# borrowed from XML::LibXSLT
+
+sub perl_dispatcher {
+ my $func = shift;
+ my @params = @_;
+ my @perlParams;
+
+ my $i = 0;
+ while (@params) {
+ my $type = shift(@params);
+ if ($type eq 'XML::LibXML::Literal' or
+ $type eq 'XML::LibXML::Number' or
+ $type eq 'XML::LibXML::Boolean')
+ {
+ my $val = shift(@params);
+ unshift(@perlParams, $USE_LIBXML_DATA_TYPES ? $type->new($val) : $val);
+ }
+ elsif ($type eq 'XML::LibXML::NodeList') {
+ my $node_count = shift(@params);
+ unshift(@perlParams, $type->new(splice(@params, 0, $node_count)));
+ }
+ }
+
+ $func = "main::$func" unless ref($func) || $func =~ /(.+)::/;
+ no strict 'refs';
+ my $res = $func->(@perlParams);
+ return $res;
+}
+
1;
|