/* * call-seq: * evaluate(search_path, handler = nil) * * Evaluate the +search_path+ returning an XML::XPath object. */ static VALUE evaluate(int argc, VALUE *argv, VALUE self) { VALUE search_path, xpath_handler; VALUE thing = Qnil; xmlXPathContextPtr ctx; xmlXPathObjectPtr xpath; xmlChar *query; Data_Get_Struct(self, xmlXPathContext, ctx); if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1) xpath_handler = Qnil; query = (xmlChar *)StringValuePtr(search_path); if(Qnil != xpath_handler) { /* FIXME: not sure if this is the correct place to shove private data. */ ctx->userData = (void *)xpath_handler; xmlXPathRegisterFuncLookup(ctx, lookup, (void *)xpath_handler); } xmlResetLastError(); xmlSetStructuredErrorFunc(NULL, xpath_exception_handler); /* For some reason, xmlXPathEvalExpression will blow up with a generic error */ /* when there is a non existent function. */ xmlSetGenericErrorFunc(NULL, xpath_generic_exception_handler); xpath = xmlXPathEvalExpression(query, ctx); xmlSetStructuredErrorFunc(NULL, NULL); xmlSetGenericErrorFunc(NULL, NULL); if(xpath == NULL) { VALUE xpath = rb_const_get(mNokogiriXml, rb_intern("XPath")); VALUE klass = rb_const_get(xpath, rb_intern("SyntaxError")); xmlErrorPtr error = xmlGetLastError(); rb_exc_raise(Nokogiri_wrap_xml_syntax_error(klass, error)); } assert(ctx->doc); assert(DOC_RUBY_OBJECT_TEST(ctx->doc)); switch(xpath->type) { case XPATH_STRING: thing = NOKOGIRI_STR_NEW2(xpath->stringval); break; case XPATH_NODESET: if(NULL == xpath->nodesetval) { thing = Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL), DOC_RUBY_OBJECT(ctx->doc)); } else { thing = Nokogiri_wrap_xml_node_set(xpath->nodesetval, DOC_RUBY_OBJECT(ctx->doc)); } break; case XPATH_NUMBER: thing = rb_float_new(xpath->floatval); break; case XPATH_BOOLEAN: thing = xpath->boolval == 1 ? Qtrue : Qfalse; break; default: thing = Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL), DOC_RUBY_OBJECT(ctx->doc)); } xmlXPathFreeNodeSetList(xpath); return thing; }