    /*
     * 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;
    }