From: Petr P. <pa...@us...> - 2003-11-03 18:09:41
|
Update of /cvsroot/perl-xml/XML-LibXML-XPathContext In directory sc8-pr-cvs1:/tmp/cvs-serv27421 Modified Files: perl-libxml-mm.c XPathContext.xs XPathContext.pm README Changes Log Message: * simplified variable lookup code to use a C structure instead of a perl AV* * made XPathContext reentrant (by saving the state before a callback and restoring it afterwards). * added get/setContextSize, get/setContextPosition * added getVarLookupFunc * added some tests and documentation for the new features * applied last LibXML patch for perl-libxml-mm.c Index: perl-libxml-mm.c =================================================================== RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/perl-libxml-mm.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- perl-libxml-mm.c 20 May 2003 15:25:50 -0000 1.2 +++ perl-libxml-mm.c 3 Nov 2003 18:09:38 -0000 1.3 @@ -5,7 +5,7 @@ * Basic concept: * perl varies in the implementation of UTF8 handling. this header (together * with the c source) implements a few functions, that can be used from within - * the core module inorder to avoid cascades of c pragmas + * the core module in order to avoid cascades of c pragmas */ #ifdef __cplusplus @@ -28,6 +28,7 @@ #include <libgdome/gdome-libxml-util.h> #endif + #include "perl-libxml-sax.h" #ifdef __cplusplus @@ -132,7 +133,7 @@ #define xpc_PmmENCODING(node) node->encoding #define xpc_PmmNodeEncoding(node) ((xpc_ProxyNodePtr)(node->_private))->encoding - +#define xpc_PmmDocEncoding(node) (node->charset) /* creates a new proxy node from a given node. this function is aware * about the fact that a node may already has a proxy structure. */ @@ -142,7 +143,7 @@ xpc_ProxyNodePtr proxy = NULL; if ( node == NULL ) { - warn( "no node found\n" ); + xs_warn( "no node found\n" ); return NULL; } @@ -173,9 +174,12 @@ frag = xmlNewDocFragment( doc ); retval = xpc_PmmNewNode(frag); - if ( doc ) { + if ( doc != NULL ) { xs_warn("inc document\n"); - xpc_PmmREFCNT_inc(((xpc_ProxyNodePtr)doc->_private)); + /* under rare circumstances _private is not set correctly? */ + if ( doc->_private != NULL ) { + xpc_PmmREFCNT_inc(((xpc_ProxyNodePtr)doc->_private)); + } retval->owner = (xmlNodePtr)doc; } @@ -203,7 +207,7 @@ } break; case XML_DTD_NODE: - if ( node->doc ) { + if ( node->doc != NULL ) { if ( node->doc->extSubset != (xmlDtdPtr)node && node->doc->intSubset != (xmlDtdPtr)node ) { xs_warn( "PFN: XML_DTD_NODE\n"); @@ -233,7 +237,7 @@ xpc_ProxyNodePtr owner = NULL; int retval = 0; - if ( node ) { + if ( node != NULL ) { retval = xpc_PmmREFCNT(node)--; if ( xpc_PmmREFCNT(node) <= 0 ) { xs_warn( "NODE DELETATION\n" ); @@ -305,7 +309,7 @@ xs_warn(" return new perl node\n"); xs_warn( CLASS ); - if ( node->_private ) { + if ( node->_private != NULL ) { dfProxy = xpc_PmmNewNode(node); } else { @@ -467,7 +471,7 @@ void xpc_PmmFixOwnerList( xmlNodePtr list, xpc_ProxyNodePtr parent ) { - if ( list ) { + if ( list != NULL ) { xmlNodePtr iterator = list; while ( iterator != NULL ) { switch ( iterator->type ) { @@ -528,7 +532,7 @@ break; } - if ( xpc_PmmOWNER(nodetofix) ) { + if ( xpc_PmmOWNER(nodetofix) != NULL ) { oldParent = xpc_PmmOWNERPO(nodetofix); } @@ -546,7 +550,7 @@ xpc_PmmOWNER(nodetofix) = NULL; } - if ( oldParent && oldParent != nodetofix ) + if ( oldParent != NULL && oldParent != nodetofix ) xpc_PmmREFCNT_dec(oldParent); if ( xpc_PmmNODE(nodetofix)->type != XML_ATTRIBUTE_NODE @@ -605,7 +609,7 @@ { xmlParserCtxtPtr libnode = NULL; int retval = 0; - if ( node ) { + if ( node != NULL ) { retval = xpc_PmmREFCNT(node)--; if ( xpc_PmmREFCNT(node) <= 0 ) { xs_warn( "NODE DELETATION\n" ); @@ -689,21 +693,19 @@ xmlChar *retval = NULL; xmlBufferPtr in = NULL, out = NULL; - if ( charset == 1 ) { + if ( charset == XML_CHAR_ENCODING_UTF8 ) { /* warn("use UTF8 for encoding ... %s ", string); */ - return xmlStrdup( string ); - } - - if ( charset > 1 ) { - /* warn( "use document encoding %s (%d)", encoding, charset ); */ - coder= xmlGetCharEncodingHandler( charset ); - } + return xmlStrdup( string ); + } else if ( charset == XML_CHAR_ENCODING_ERROR ){ /* warn("no standard encoding %s\n", encoding); */ coder =xmlFindCharEncodingHandler( (const char *)encoding ); } - else { + else if ( charset == XML_CHAR_ENCODING_NONE ){ xs_warn("no encoding found \n"); + } else { + /* warn( "use document encoding %s (%d)", encoding, charset ); */ + coder= xmlGetCharEncodingHandler( charset ); } if ( coder != NULL ) { @@ -716,7 +718,7 @@ /* warn( "encoded string is %s" , retval); */ } else { - xs_warn( "b0rked encoiding!\n"); + /* warn( "b0rked encoiding!\n"); */ } xmlBufferFree( in ); @@ -735,21 +737,16 @@ xmlChar *retval = NULL; xmlBufferPtr in = NULL, out = NULL; - if ( charset == 1 ) { - - return xmlStrdup( string ); - } - - if ( charset > 1 ) { - /* warn( "use document encoding %s", encoding ); */ - coder= xmlGetCharEncodingHandler( charset ); - } + if ( charset == XML_CHAR_ENCODING_UTF8 ) { + return xmlStrdup( string ); + } else if ( charset == XML_CHAR_ENCODING_ERROR ){ - /* warn("no standard encoding\n"); */ - coder = xmlFindCharEncodingHandler( (const char *) encoding ); + coder =xmlFindCharEncodingHandler( (const char *)encoding ); } - else { - xs_warn("no encoding found\n"); + else if ( charset == XML_CHAR_ENCODING_NONE ){ + xs_warn("no encoding found \n"); + } else { + coder= xmlGetCharEncodingHandler( charset ); } if ( coder != NULL ) { @@ -759,7 +756,7 @@ xmlBufferCat( in, string ); if ( xmlCharEncOutFunc( coder, out, in ) >= 0 ) { - retval = xmlStrdup(out->content); + retval = xmlCharStrndup(xmlBufferContent(out), xmlBufferLength(out)); } else { xs_warn("decoding error \n"); @@ -805,7 +802,6 @@ xpc_PmmDecodeString( const char *encoding, const xmlChar *string){ char *ret=NULL; xmlCharEncoding enc; - xmlBufferPtr in = NULL, out = NULL; xmlCharEncodingHandlerPtr coder = NULL; if ( string != NULL ) { @@ -913,14 +909,23 @@ if ( refnode != NULL ) { xmlDocPtr real_doc = refnode->doc; - if ( real_doc && real_doc->encoding != NULL ) { + if ( real_doc != NULL && real_doc->encoding != NULL ) { - xmlChar * decoded = xpc_PmmFastDecodeString( xpc_PmmNodeEncoding(real_doc) , - (const xmlChar *)string, - (const xmlChar*)real_doc->encoding); + xmlChar * decoded = xpc_PmmDecodeString( (const xmlChar*)real_doc->encoding, + (const xmlChar *)string ); len = xmlStrlen( decoded ); - if ( real_doc->charset == XML_CHAR_ENCODING_UTF8 ) { + if ( xpc_PmmDocEncoding(real_doc) == XML_CHAR_ENCODING_UTF8 + /* most probably true, since libxml2 always + * sets doc->charset to UTF8, see tree.c: + * + * The in memory encoding is always UTF8 + * This field will never change and would + * be obsolete if not for binary compatibility. + */ + + && (real_doc->encoding == NULL || + xmlParseCharEncoding(real_doc->encoding)==XML_CHAR_ENCODING_UTF8 )) { /* create an UTF8 string. */ xs_warn("set UTF8 string"); /* create the SV */ @@ -960,7 +965,7 @@ perl. in this cases the library assumes, all strings are in UTF8. if a programmer likes to have the intelligent code, he needs to upgrade perl */ -#ifdef HAVE_UTF8 + if ( refnode != NULL ) { xmlDocPtr real_dom = refnode->doc; xs_warn("have node!"); @@ -976,15 +981,17 @@ xs_warn( "no undefs" ); #ifdef HAVE_UTF8 xs_warn( "use UTF8" ); - if( !DO_UTF8(scalar) && real_dom->encoding != NULL ) { + if( !DO_UTF8(scalar) && real_dom != NULL && real_dom->encoding != NULL ) { xs_warn( "string is not UTF8\n" ); #else - if ( real_dom->encoding != NULL ) { + if ( real_dom != NULL && real_dom->encoding != NULL ) { #endif xs_warn( "xpc_domEncodeString!" ); - ts= xpc_PmmFastEncodeString( xpc_PmmNodeEncoding(real_dom), - string, - (const xmlChar*)real_dom->encoding ); + /* if ( string == NULL || *string == 0 ) warn("string is empty" ); */ + + ts= xpc_PmmEncodeString( (const xmlChar*)real_dom->encoding, + string ); + xs_warn( "done!" ); if ( string != NULL ) { xmlFree(string); @@ -995,7 +1002,7 @@ xs_warn( "no encoding set, use UTF8!\n" ); } } - if ( string == NULL ) xs_warn( "string is NULL\n" ); + /* if ( string == NULL ) warn( "string is NULL\n" ); */ return string; } else { @@ -1008,7 +1015,6 @@ } } xs_warn("no encoding !!"); -#endif return xpc_Sv2C( scalar, NULL ); } Index: XPathContext.xs =================================================================== RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/XPathContext.xs,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- XPathContext.xs 21 Sep 2003 10:05:05 -0000 1.36 +++ XPathContext.xs 3 Nov 2003 18:09:38 -0000 1.37 @@ -25,7 +25,9 @@ static SV * xpc_LibXML_error = NULL; -#define xpc_LibXML_init_error() xpc_LibXML_error = NEWSV(0, 512); \ +/* NEWSV(0, 512); \ */ +#define xpc_LibXML_init_error() if (xpc_LibXML_error == NULL || !SvOK(xpc_LibXML_error)) \ + xpc_LibXML_error = NEWSV(0,512); \ sv_setpvn(xpc_LibXML_error, "", 0); \ xmlSetGenericErrorFunc( NULL , \ (xmlGenericErrorFunc)xpc_LibXML_error_handler); @@ -36,8 +38,10 @@ struct _XPathContextData { SV* node; - int lock; + int lock; /* currently unnecessary */ HV* pool; + SV* varLookup; + SV* varData; }; typedef struct _XPathContextData XPathContextData; typedef XPathContextData* XPathContextDataPtr; @@ -185,6 +189,61 @@ } +/* save XPath context and XPathContextDATA for recursion */ +static xmlXPathContextPtr +xpc_LibXML_save_context(xmlXPathContextPtr ctxt) +{ + xmlXPathContextPtr copy; + copy = xmlMalloc(sizeof(xmlXPathContext)); + if (copy) { + /* backup ctxt */ + memcpy(copy, ctxt, sizeof(xmlXPathContext)); + /* clear namespaces so that they are not freed and overwritten + by configure_namespaces */ + ctxt->namespaces = NULL; + /* backup data */ + XPathContextDATA(copy) = xmlMalloc(sizeof(XPathContextData)); + if (XPathContextDATA(copy)) { + memcpy(XPathContextDATA(copy), XPathContextDATA(ctxt),sizeof(XPathContextData)); + /* clear ctxt->pool, so that it is not used freed during re-entrance */ + XPathContextDATA(ctxt)->pool = NULL; + } + } + return copy; +} + +/* restore XPath context and XPathContextDATA from a saved copy */ +static void +xpc_LibXML_restore_context(xmlXPathContextPtr ctxt, xmlXPathContextPtr copy) +{ + /* cleanup */ + if (XPathContextDATA(ctxt)) { + /* cleanup newly created pool */ + if (XPathContextDATA(ctxt)->pool != NULL && + SvOK(XPathContextDATA(ctxt)->pool)) { + SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool); + } + } + if (ctxt->namespaces) { + /* free namespaces allocated during recursion */ + xmlFree( ctxt->namespaces ); + } + + /* restore context */ + if (copy) { + /* 1st restore our data */ + if (XPathContextDATA(copy)) { + memcpy(XPathContextDATA(ctxt),XPathContextDATA(copy),sizeof(XPathContextData)); + xmlFree(XPathContextDATA(copy)); + XPathContextDATA(copy) = XPathContextDATA(ctxt); + } + /* now copy the rest */ + memcpy(ctxt, copy, sizeof(xmlXPathContext)); + xmlFree(copy); + } +} + + /* **************************************************************** * Variable Lookup * **************************************************************** */ @@ -195,37 +254,40 @@ const xmlChar *ns_uri) { xmlXPathObjectPtr ret; - SV ** lookup_func; - SV ** lookup_data; + xmlXPathContextPtr ctxt; + xmlXPathContextPtr copy; + XPathContextDataPtr data; I32 count; dSP; - SV * data; - SV ** fetch; - data = (SV *) varLookupData; - if (varLookupData == NULL || !SvROK(data) || - SvTYPE(SvRV(data)) != SVt_PVAV) { - croak("XPathContext: lost variable lookup data structure!"); - } - - lookup_func = av_fetch((AV *) SvRV(data),0,0 ); - if ( lookup_func == NULL || !SvROK(*lookup_func) || SvTYPE(SvRV(*lookup_func)) != SVt_PVCV ) { + ctxt = (xmlXPathContextPtr) varLookupData; + if ( ctxt == NULL ) + croak("XPathContext: missing xpath context"); + data = XPathContextDATA(ctxt); + if ( data == NULL ) + croak("XPathContext: missing xpath context private data"); + if ( data->varLookup == NULL || !SvROK(data->varLookup) || + SvTYPE(SvRV(data->varLookup)) != SVt_PVCV ) croak("XPathContext: lost variable lookup function!"); - } - lookup_data = av_fetch((AV *) SvRV(data),1,0 ); ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs( (lookup_data != NULL) ? *lookup_data : &PL_sv_undef ); + XPUSHs( (data->varData != NULL) ? data->varData : &PL_sv_undef ); XPUSHs(sv_2mortal(xpc_C2Sv(name,NULL))); XPUSHs(sv_2mortal(xpc_C2Sv(ns_uri,NULL))); - PUTBACK ; - count = perl_call_sv(*lookup_func, G_SCALAR|G_EVAL); + /* save context to allow recursive usage of XPathContext */ + copy = xpc_LibXML_save_context(ctxt); + PUTBACK ; + count = perl_call_sv(data->varLookup, G_SCALAR|G_EVAL); SPAGAIN; + + /* restore the xpath context */ + xpc_LibXML_restore_context(ctxt, copy); + if (SvTRUE(ERRSV)) { POPs; croak("XPathContext: error coming back from variable lookup function. %s", SvPV_nolen(ERRSV)); @@ -260,6 +322,7 @@ SV **perl_function; dSP; SV * data; + xmlXPathContextPtr copy; /* warn("entered xpc_LibXML_generic_extension_function for %s\n",ctxt->context->function); */ data = (SV *) ctxt->context->funcLookupData; @@ -362,14 +425,18 @@ xmlXPathFreeObject(obj); } + /* save context to allow recursive usage of XPathContext */ + copy = xpc_LibXML_save_context(ctxt->context); + /* 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); - + count = perl_call_sv(perl_dispatch, G_SCALAR|G_EVAL); SPAGAIN; + /* restore the xpath context */ + xpc_LibXML_restore_context(ctxt->context, copy); + if (SvTRUE(ERRSV)) { POPs; croak("XPathContext: error coming back from perl-dispatcher in pm file. %s", SvPV_nolen(ERRSV)); @@ -453,6 +520,8 @@ XPathContextDATA(ctxt)->lock = 0; XPathContextDATA(ctxt)->pool = NULL; + XPathContextDATA(ctxt)->varLookup = NULL; + XPathContextDATA(ctxt)->varData = NULL; xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document", @@ -478,6 +547,14 @@ SvOK(XPathContextDATA(ctxt)->node)) { SvREFCNT_dec(XPathContextDATA(ctxt)->node); } + if (XPathContextDATA(ctxt)->varLookup != NULL && + SvOK(XPathContextDATA(ctxt)->varLookup)) { + SvREFCNT_dec(XPathContextDATA(ctxt)->varLookup); + } + if (XPathContextDATA(ctxt)->varData != NULL && + SvOK(XPathContextDATA(ctxt)->varData)) { + SvREFCNT_dec(XPathContextDATA(ctxt)->varData); + } if (XPathContextDATA(ctxt)->pool != NULL && SvOK(XPathContextDATA(ctxt)->pool)) { SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool); @@ -488,10 +565,6 @@ 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); @@ -517,6 +590,32 @@ OUTPUT: RETVAL +int +getContextPosition( self ) + SV * self + INIT: + xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); + if ( ctxt == NULL ) { + croak("XPathContext: missing xpath context"); + } + CODE: + RETVAL = ctxt->proximityPosition; + OUTPUT: + RETVAL + +int +getContextSize( self ) + SV * self + INIT: + xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); + if ( ctxt == NULL ) { + croak("XPathContext: missing xpath context"); + } + CODE: + RETVAL = ctxt->contextSize; + OUTPUT: + RETVAL + void setContextNode( self , pnode ) SV * self @@ -536,6 +635,38 @@ XPathContextDATA(ctxt)->node = NULL; } +void +setContextPosition( self , position ) + SV * self + int position + INIT: + xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); + if ( ctxt == NULL ) + croak("XPathContext: missing xpath context"); + if ( position < 0 || position > ctxt->contextSize ) + croak("XPathContext: invalid position"); + PPCODE: + ctxt->proximityPosition = position; + +void +setContextSize( self , size ) + SV * self + int size + INIT: + xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); + if ( ctxt == NULL ) + croak("XPathContext: missing xpath context"); + if ( size < -1 ) + croak("XPathContext: invalid size"); + PPCODE: + ctxt->contextSize = size; + if ( size == 0 ) + ctxt->proximityPosition = 0; + else if ( size > 0 ) + ctxt->proximityPosition = 1; + else + ctxt->proximityPosition = -1; + void registerNs( pxpath_context, prefix, ns_uri ) SV * pxpath_context @@ -583,23 +714,30 @@ getVarLookupData( self ) SV * self INIT: - SV ** lookup_data; xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); if ( ctxt == NULL ) { croak("XPathContext: missing xpath context"); } - xpc_LibXML_configure_xpathcontext(ctxt); CODE: - if (ctxt->varLookupData != NULL && - SvROK((SV*)(ctxt->varLookupData)) && - SvTYPE(SvRV((SV*)(ctxt->varLookupData))) == SVt_PVAV) { - lookup_data = av_fetch((AV *) SvRV((SV*)(ctxt->varLookupData)),1,0); - if (lookup_data != NULL) { - SvREFCNT_inc(*lookup_data); - RETVAL = *lookup_data; - } else { - RETVAL = &PL_sv_undef; - } + if(XPathContextDATA(ctxt)->varData != NULL) { + RETVAL = newSVsv(XPathContextDATA(ctxt)->varData); + } else { + RETVAL = &PL_sv_undef; + } + OUTPUT: + RETVAL + +SV* +getVarLookupFunc( self ) + SV * self + INIT: + xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self)); + if ( ctxt == NULL ) { + croak("XPathContext: missing xpath context"); + } + CODE: + if(XPathContextDATA(ctxt)->varData != NULL) { + RETVAL = newSVsv(XPathContextDATA(ctxt)->varLookup); } else { RETVAL = &PL_sv_undef; } @@ -613,38 +751,37 @@ SV * lookup_data PREINIT: xmlXPathContextPtr ctxt = NULL; + XPathContextDataPtr data = NULL; SV* pfdr; INIT: ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context)); - if ( ctxt == NULL ) { + if ( ctxt == NULL ) croak("XPathContext: missing xpath context"); - } + data = XPathContextDATA(ctxt); + if ( data == NULL ) + croak("XPathContext: missing xpath context private data"); xpc_LibXML_configure_xpathcontext(ctxt); + /* free previous lookup function and data */ + if (data->varLookup && SvOK(data->varLookup)) + SvREFCNT_dec(data->varLookup); + if (data->varData && SvOK(data->varData)) + SvREFCNT_dec(data->varData); + data->varLookup=NULL; + data->varData=NULL; + PPCODE: if (SvOK(lookup_func)) { if ( SvROK(lookup_func) && SvTYPE(SvRV(lookup_func)) == SVt_PVCV ) { - pfdr = newRV_inc((SV*) newAV()); - av_push((AV *)SvRV(pfdr), newSVsv(lookup_func)); - av_push((AV *)SvRV(pfdr), newSVsv(lookup_data)); + data->varLookup = newSVsv(lookup_func); + if (SvOK(lookup_data)) + data->varData = newSVsv(lookup_data); + xmlXPathRegisterVariableLookup(ctxt, + xpc_LibXML_generic_variable_lookup, ctxt); + if (ctxt->varLookupData==NULL || ctxt->varLookupData != ctxt) { + croak( "XPathContext: registration failure" ); + } } else { croak("XPathContext: 1st argument is not a CODE reference"); } - } - if (ctxt->varLookupData != NULL) { - /* free previous lookup data */ - if (SvTYPE(SvRV((SV *)ctxt->varLookupData)) == SVt_PVAV) { - SvREFCNT_dec((SV *)ctxt->varLookupData); - ctxt->varLookupData = NULL; - ctxt->varLookupFunc = NULL; - } else { - croak("XPathContext: cannot register: varLookupData slot already occupied"); - } - } - PPCODE: - if (SvOK(lookup_func)) { - xmlXPathRegisterVariableLookup(ctxt, xpc_LibXML_generic_variable_lookup, pfdr); - if (ctxt->varLookupData==NULL || ctxt->varLookupData != pfdr) { - croak( "XPathContext: registration failure" ); - } } else { /* unregister */ xmlXPathRegisterVariableLookup(ctxt, NULL, NULL); @@ -801,7 +938,6 @@ } xmlFree(xpath); - sv_2mortal( xpc_LibXML_error ); xpc_LibXML_croak_error(); if ( nodelist ) { @@ -896,7 +1032,6 @@ xmlFree( xpath ); - sv_2mortal( xpc_LibXML_error ); xpc_LibXML_croak_error(); if (found) { Index: XPathContext.pm =================================================================== RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/XPathContext.pm,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- XPathContext.pm 22 Sep 2003 08:02:56 -0000 1.30 +++ XPathContext.pm 3 Nov 2003 18:09:38 -0000 1.31 @@ -7,7 +7,7 @@ use XML::LibXML::NodeList; -$VERSION = '0.05'; +$VERSION = '0.06'; require DynaLoader; @ISA = qw(DynaLoader); @@ -55,15 +55,15 @@ $prev_node = $self->getContextNode(); $self->setContextNode($node); } - $self->_enter; +# $self->_enter; # lock my @ret; eval { @ret = $self->$method($xpath); }; - $self->_leave; + $self->_leave; # unlock and free node-pool $self->setContextNode($prev_node) if ref($node); - if ($@) { die $@; } + if ($@) { die "ERROR: $@"; } return @ret; } @@ -147,6 +147,11 @@ my $node = $xc->getContextNode; $xc->setContextNode($node); + my $position = $xc->getContextPosition; + $xc->setContextPosition($position); + my $size = $xc->getContextSize; + $xc->setContextSize($size); + $xc->registerNs($prefix, $namespace_uri); $xc->unregisterNs($prefix); my $namespace_uri = $xc->lookupNs($prefix); @@ -158,6 +163,8 @@ $xc->registerVarLookupFunc(sub { ... }, $data); $xc->unregisterVarLookupFunc($name); + $data = $xc->getVarLookupData(); + $sub = $xc->getVarLookupFunc(); my @nodes = $xc->findnodes($xpath); my @nodes = $xc->findnodes($xpath, $context_node); @@ -191,6 +198,10 @@ defining variable lookup functions in Perl. +=item 3 + +cheating the context about current proximity position and context size + =back =head1 EXAMPLES @@ -369,20 +380,49 @@ Set the current context node. -=back +=item B<setContextPosition($position)> -=head1 BUGS AND CAVEATS +Set the current proximity position. By default, this value is -1 (and +evaluating XPath function position() in the initial context raises an +XPath error), but can be set to any value up to context size. This +usually only serves to cheat the XPath engine to return given position +when position() XPath function is called. Setting this value to -1 +restores the default behavior. -XML::LibXML::XPathContext objects are not reentrant. It means you -cannot register a Perl function with a XML::LibXML::XPathContext -object if this Perl function uses itself the same -XML::LibXML::XPathContext object internally. +=item B<getContextPosition()> -For example, the following code will not work: +Get the current proximity position. - my $xc = XML::LibXML::XPathContext->new($node); - $xc->registerFunction('func', sub { $xc->findvalue('1') }); - my $result = $xc->findvalue('func()'); +=item B<setContextSize($size)> + +Set the current size. By default, this value is -1 (and evaluating +XPath function last() in the initial context raises an XPath error), +but can be set to any non-negative value. This usually only serves to +cheat the XPath engine to return the given value when last() XPath +function is called. If context size is set to 0, position is +automatically also set to 0. If context size is positive, position is +automatically set to 1. Setting context size to -1 restores the +default behavior. + +=item B<getContextPosition()> + +Get the current proximity position. + +=item B<setContextNode($node)> + +Set the current context node. + +=back + +=head1 BUGS AND CAVEATS + +From version 0.06, XML::LibXML::XPathContext objects B<are> reentrant, +meaning that you can call methods of an XML::LibXML::XPathContext even +from XPath extension functions registered with the same object or from +a variable lookup function. On the other hand, you should rather +avoid registering new extension functions, namespaces and a variable +lookup function from within extension functions and a variable lookup +function, unless you want to experience untested behavior. =head1 AUTHORS Index: README =================================================================== RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/README,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- README 25 Jul 2003 12:51:03 -0000 1.6 +++ README 3 Nov 2003 18:09:38 -0000 1.7 @@ -10,6 +10,11 @@ my $node = $xc->getContextNode; $xc->setContextNode($node); + my $position = $xc->getContextPosition; + $xc->setContextPosition($position); + my $size = $xc->getContextSize; + $xc->setContextSize($size); + $xc->registerNs($prefix, $namespace_uri); $xc->unregisterNs($prefix); my $namespace_uri = $xc->lookupNs($prefix); @@ -21,6 +26,8 @@ $xc->registerVarLookupFunc(sub { ... }, $data); $xc->unregisterVarLookupFunc($name); + $data = $xc->getVarLookupData(); + $sub = $xc->getVarLookupFunc(); my @nodes = $xc->findnodes($xpath); my @nodes = $xc->findnodes($xpath, $context_node); @@ -43,6 +50,9 @@ 3 defining variable lookup functions in Perl. + 3 cheating the context about current proximity position and context + size + EXAMPLES Find all paragraph nodes in XHTML document This example demonstrates *registerNs()* usage: @@ -190,17 +200,41 @@ setContextNode($node) Set the current context node. -BUGS AND CAVEATS - XML::LibXML::XPathContext objects are not reentrant. It means you cannot - register a Perl function with a XML::LibXML::XPathContext object if this - Perl function uses itself the same XML::LibXML::XPathContext object - internally. + setContextPosition($position) + Set the current proximity position. By default, this value is -1 + (and evaluating XPath function position() in the initial context + raises an XPath error), but can be set to any value up to context + size. This usually only serves to cheat the XPath engine to return + given position when position() XPath function is called. Setting + this value to -1 restores the default behavior. - For example, the following code will not work: + getContextPosition() + Get the current proximity position. - my $xc = XML::LibXML::XPathContext->new($node); - $xc->registerFunction('func', sub { $xc->findvalue('1') }); - my $result = $xc->findvalue('func()'); + setContextSize($size) + Set the current size. By default, this value is -1 (and evaluating + XPath function last() in the initial context raises an XPath error), + but can be set to any non-negative value. This usually only serves + to cheat the XPath engine to return the given value when last() + XPath function is called. If context size is set to 0, position is + automatically also set to 0. If context size is positive, position + is automatically set to 1. Setting context size to -1 restores the + default behavior. + + getContextPosition() + Get the current proximity position. + + setContextNode($node) + Set the current context node. + +BUGS AND CAVEATS + From version 0.06, XML::LibXML::XPathContext objects are reentrant, + meaning that you can call methods of an XML::LibXML::XPathContext even + from XPath extension functions registered with the same object or from a + variable lookup function. On the other hand, you should rather avoid + registering new extension functions, namespaces and a variable lookup + function from within extension functions and a variable lookup function, + unless you want to experience untested behavior. AUTHORS Based on XML::LibXML and XML::XSLT code by Matt Sergeant and Christian Index: Changes =================================================================== RCS file: /cvsroot/perl-xml/XML-LibXML-XPathContext/Changes,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- Changes 22 Sep 2003 08:02:26 -0000 1.12 +++ Changes 3 Nov 2003 18:09:38 -0000 1.13 @@ -2,6 +2,22 @@ Revision history for Perl module XML::LibXML::XPathContext. +0.06 Mon Nov 3 2003 + +* simplified variable lookup code to use a C structure instead of + a perl AV* + +* made XPathContext reentrant (by saving the state before + a callback and restoring it afterwards). + +* added get/setContextSize, get/setContextPosition + +* added getVarLookupFunc + +* added some tests and documentation for the new features + +* applied last LibXML patch for perl-libxml-mm.c + 0.05 Mon Sep 22 2003 * lookupNs() method added |