/home/.cpanm/work/1759492321.34808/XML-LibXML-2.0210
/* $Id$ * * This is free software, you may use it and distribute it under the same terms as * Perl itself. * * Copyright 2001-2003 AxKit.com Ltd., 2002-2006 Christian Glahn, 2006-2009 Petr Pajas */ #include <libxml/tree.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/uri.h> #include "EXTERN.h" #include "dom.h" #include "xpath.h" void perlDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj = NULL, obj2 = NULL; xmlChar *base = NULL, *URI = NULL; if ((nargs < 1) || (nargs > 2)) { ctxt->error = XPATH_INVALID_ARITY; return; } if (ctxt->value == NULL) { ctxt->error = XPATH_INVALID_TYPE; return; } if (nargs == 2) { if (ctxt->value->type != XPATH_NODESET) { ctxt->error = XPATH_INVALID_TYPE; return; } obj2 = valuePop(ctxt); } /* first assure the XML::LibXML error handler is deactivated otherwise strange things might happen */ if (ctxt->value->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; obj = valuePop(ctxt); ret = xmlXPathNewNodeSet(NULL); if (obj->nodesetval) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); if (nargs == 2) { valuePush(ctxt, xmlXPathObjectCopy(obj2)); } else { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); } perlDocumentFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); valuePush(ctxt, ret); /* reset the error old error handler before leaving */ return; } /* * Make sure it's converted to a string */ xmlXPathStringFunction(ctxt, 1); if (ctxt->value->type != XPATH_STRING) { ctxt->error = XPATH_INVALID_TYPE; if (obj2 != NULL) xmlXPathFreeObject(obj2); /* reset the error old error handler before leaving */ return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if ((obj2 != NULL) && (obj2->nodesetval != NULL) && (obj2->nodesetval->nodeNr > 0)) { xmlNodePtr target; target = obj2->nodesetval->nodeTab[0]; if (target->type == XML_ATTRIBUTE_NODE) { target = ((xmlAttrPtr) target)->parent; } base = xmlNodeGetBase(target->doc, target); } else { base = xmlNodeGetBase(ctxt->context->node->doc, ctxt->context->node); } URI = xmlBuildURI(obj->stringval, base); if (base != NULL) xmlFree(base); if (URI == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if (xmlStrEqual(ctxt->context->node->doc->URL, URI)) { valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)ctxt->context->node->doc)); } else { xmlDocPtr doc; doc = xmlParseFile((const char *)URI); if (doc == NULL) valuePush(ctxt, xmlXPathNewNodeSet(NULL)); else { /* TODO: use XPointer of HTML location for fragment ID */ /* pbm #xxx can lead to location sets, not nodesets :-) */ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc)); } } xmlFree(URI); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); /* reset the error old error handler before leaving */ } /** * Most of the code is stolen from testXPath. * The almost only thing I added, is the storeing of the data, so * we can access the data easily - or say more easiely than through * libxml2. **/ xmlXPathObjectPtr domXPathFind( xmlNodePtr refNode, xmlChar * path, int to_bool ) { xmlXPathObjectPtr res = NULL; xmlXPathCompExprPtr comp; comp = xmlXPathCompile( path ); if ( comp == NULL ) { return NULL; } res = domXPathCompFind(refNode,comp,to_bool); xmlXPathFreeCompExpr(comp); return res; } xmlXPathObjectPtr domXPathCompFind( xmlNodePtr refNode, xmlXPathCompExprPtr comp, int to_bool ) { xmlXPathObjectPtr res = NULL; if ( refNode != NULL && comp != NULL ) { xmlXPathContextPtr ctxt; xmlDocPtr tdoc = NULL; xmlNodePtr froot = refNode; if ( comp == NULL ) { return NULL; } if ( refNode->doc == NULL ) { /* if one XPaths a node from a fragment, libxml2 will refuse the lookup. this is not very useful for XML scripters. thus we need to create a temporary document to make libxml2 do it's job correctly. */ tdoc = xmlNewDoc( NULL ); /* find refnode's root node */ while ( froot != NULL ) { if ( froot->parent == NULL ) { break; } froot = froot->parent; } xmlAddChild((xmlNodePtr)tdoc, froot); xmlSetTreeDoc(froot, tdoc); /* probably no need to clean psvi */ froot->doc = tdoc; /* refNode->doc = tdoc; */ } /* prepare the xpath context */ ctxt = xmlXPathNewContext( refNode->doc ); ctxt->node = refNode; /* get the namespace information */ if (refNode->type == XML_DOCUMENT_NODE) { ctxt->namespaces = xmlGetNsList( refNode->doc, xmlDocGetRootElement( refNode->doc ) ); } else { ctxt->namespaces = xmlGetNsList(refNode->doc, refNode); } ctxt->nsNr = 0; if (ctxt->namespaces != NULL) { while (ctxt->namespaces[ctxt->nsNr] != NULL) ctxt->nsNr++; } xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document", perlDocumentFunction); if (to_bool) { #if LIBXML_VERSION >= 20627 int val = xmlXPathCompiledEvalToBoolean(comp, ctxt); res = xmlXPathNewBoolean(val); #else res = xmlXPathCompiledEval(comp, ctxt); if (res!=NULL) { int val = xmlXPathCastToBoolean(res); xmlXPathFreeObject(res); res = xmlXPathNewBoolean(val); } #endif } else { res = xmlXPathCompiledEval(comp, ctxt); } if (ctxt->namespaces != NULL) { xmlFree( ctxt->namespaces ); } xmlXPathFreeContext(ctxt); if ( tdoc != NULL ) { /* after looking through a fragment, we need to drop the fake document again */ xmlSetTreeDoc(froot, NULL); /* probably no need to clean psvi */ froot->doc = NULL; froot->parent = NULL; tdoc->children = NULL; tdoc->last = NULL; /* next line is not required anymore */ /* refNode->doc = NULL; */ xmlFreeDoc( tdoc ); } } return res; } /* this function is not actually used: */ xmlNodeSetPtr domXPathSelect( xmlNodePtr refNode, xmlChar * path ) { xmlNodeSetPtr rv = NULL; xmlXPathObjectPtr res = NULL; res = domXPathFind( refNode, path, 0 ); if (res != NULL) { /* here we have to transfer the result from the internal structure to the return value */ /* get the result from the query */ /* we have to unbind the nodelist, so free object can not kill it */ rv = res->nodesetval; res->nodesetval = 0 ; } xmlXPathFreeObject(res); return rv; } /* this function is not actually used: */ xmlNodeSetPtr domXPathCompSelect( xmlNodePtr refNode, xmlXPathCompExprPtr comp ) { xmlNodeSetPtr rv = NULL; xmlXPathObjectPtr res = NULL; res = domXPathCompFind( refNode, comp, 0 ); if (res != NULL) { /* here we have to transfer the result from the internal structure to the return value */ /* get the result from the query */ /* we have to unbind the nodelist, so free object can not kill it */ rv = res->nodesetval; res->nodesetval = 0 ; } xmlXPathFreeObject(res); return rv; } /** * Most of the code is stolen from testXPath. * The almost only thing I added, is the storeing of the data, so * we can access the data easily - or say more easiely than through * libxml2. **/ xmlXPathObjectPtr domXPathFindCtxt( xmlXPathContextPtr ctxt, xmlChar * path, int to_bool ) { xmlXPathObjectPtr res = NULL; if ( ctxt->node != NULL && path != NULL ) { xmlXPathCompExprPtr comp; comp = xmlXPathCompile( path ); if ( comp == NULL ) { return NULL; } res = domXPathCompFindCtxt(ctxt,comp,to_bool); xmlXPathFreeCompExpr(comp); } return res; } xmlXPathObjectPtr domXPathCompFindCtxt( xmlXPathContextPtr ctxt, xmlXPathCompExprPtr comp, int to_bool ) { xmlXPathObjectPtr res = NULL; if ( ctxt != NULL && ctxt->node != NULL && comp != NULL ) { xmlDocPtr tdoc = NULL; xmlNodePtr froot = ctxt->node; if ( ctxt->node->doc == NULL ) { /* if one XPaths a node from a fragment, libxml2 will refuse the lookup. this is not very useful for XML scripters. thus we need to create a temporary document to make libxml2 do it's job correctly. */ tdoc = xmlNewDoc( NULL ); /* find refnode's root node */ while ( froot != NULL ) { if ( froot->parent == NULL ) { break; } froot = froot->parent; } xmlAddChild((xmlNodePtr)tdoc, froot); xmlSetTreeDoc(froot,tdoc); /* probably no need to clean psvi */ froot->doc = tdoc; /* ctxt->node->doc = tdoc; */ } if (to_bool) { #if LIBXML_VERSION >= 20627 int val = xmlXPathCompiledEvalToBoolean(comp, ctxt); res = xmlXPathNewBoolean(val); #else res = xmlXPathCompiledEval(comp, ctxt); if (res!=NULL) { int val = xmlXPathCastToBoolean(res); xmlXPathFreeObject(res); res = xmlXPathNewBoolean(val); } #endif } else { res = xmlXPathCompiledEval(comp, ctxt); } if ( tdoc != NULL ) { /* after looking through a fragment, we need to drop the fake document again */ xmlSetTreeDoc(froot,NULL); /* probably no need to clean psvi */ froot->doc = NULL; froot->parent = NULL; tdoc->children = NULL; tdoc->last = NULL; if (ctxt->node) { ctxt->node->doc = NULL; } xmlFreeDoc( tdoc ); } } return res; } xmlNodeSetPtr domXPathSelectCtxt( xmlXPathContextPtr ctxt, xmlChar * path ) { xmlNodeSetPtr rv = NULL; xmlXPathObjectPtr res = NULL; res = domXPathFindCtxt( ctxt, path, 0 ); if (res != NULL) { /* here we have to transfer the result from the internal structure to the return value */ /* get the result from the query */ /* we have to unbind the nodelist, so free object can not kill it */ rv = res->nodesetval; res->nodesetval = 0 ; } xmlXPathFreeObject(res); return rv; }
.
Edit
..
Edit
Av_CharPtrPtr.c
Edit
Av_CharPtrPtr.h
Edit
Av_CharPtrPtr.o
Edit
Changes
Edit
Devel.c
Edit
Devel.o
Edit
Devel.xs
Edit
HACKING.txt
Edit
LICENSE
Edit
LibXML.bs
Edit
LibXML.c
Edit
LibXML.o
Edit
LibXML.pm
Edit
LibXML.pod
Edit
LibXML.xs
Edit
MANIFEST
Edit
META.json
Edit
META.yml
Edit
MYMETA.json
Edit
MYMETA.yml
Edit
Makefile
Edit
Makefile.PL
Edit
README
Edit
TODO
Edit
blib
Edit
debian
Edit
docs
Edit
dom.c
Edit
dom.h
Edit
dom.o
Edit
example
Edit
lib
Edit
perl-libxml-mm.c
Edit
perl-libxml-mm.h
Edit
perl-libxml-mm.o
Edit
perl-libxml-sax.c
Edit
perl-libxml-sax.h
Edit
perl-libxml-sax.o
Edit
pm_to_blib
Edit
ppport.h
Edit
scripts
Edit
t
Edit
test
Edit
typemap
Edit
xpath.c
Edit
xpath.h
Edit
xpath.o
Edit
xpathcontext.h
Edit