Example #1
0
static void mark(xmlNodePtr node)
{
  /* it's OK if the document isn't fully realized (as in XML::Reader). */
  /* see http://github.com/tenderlove/nokogiri/issues/closed/#issue/95 */
  if (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc))
    rb_gc_mark(DOC_RUBY_OBJECT(node->doc));
}
Example #2
0
static void mark(xmlNodePtr node)
{
  xmlDocPtr doc = node->doc;
  if(doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
    if(DOC_RUBY_OBJECT_TEST(doc)) {
      rb_gc_mark(DOC_RUBY_OBJECT(doc));
    }
  } else if(node->doc->_private) {
    rb_gc_mark((VALUE)doc->_private);
  }
}
Example #3
0
/*
 * call-seq:
 *   attribute_nodes
 *
 * Get a list of attributes for this Node
 */
static VALUE attribute_nodes(VALUE self)
{
  xmlTextReaderPtr reader;
  VALUE attr ;

  Data_Get_Struct(self, xmlTextReader, reader);

  attr = rb_ary_new() ;

  if (! has_attributes(reader))
    return attr ;

  xmlNodePtr ptr = xmlTextReaderExpand(reader);
  if(ptr == NULL) return Qnil;

  // FIXME I'm not sure if this is correct.....  I don't really like pointing
  // at this document, but I have to because of the assertions in
  // the node wrapping code.
  if(! DOC_RUBY_OBJECT_TEST(ptr->doc)) {
    VALUE rb_doc = Data_Wrap_Struct(cNokogiriXmlDocument, 0, 0, ptr->doc);
    ptr->doc->_private = malloc(sizeof(nokogiriTuple));
    rb_iv_set(rb_doc, "@decorators", Qnil);
    ((nokogiriTuplePtr)(ptr->doc->_private))->doc = (void *)rb_doc;
    ((nokogiriTuplePtr)(ptr->doc->_private))->unlinkedNodes = xmlXPathNodeSetCreate(NULL);
  }
  VALUE enc = rb_iv_get(self, "@encoding");

  if(enc != Qnil && NULL == ptr->doc->encoding) {
    ptr->doc->encoding = calloc((size_t)RSTRING_LEN(enc), sizeof(char));
    strncpy(
      (char *)ptr->doc->encoding,
      StringValuePtr(enc),
      (size_t)RSTRING_LEN(enc)
    );
  }

  Nokogiri_xml_node_properties(ptr, attr);

  return attr ;
}
static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
{
  VALUE xpath_handler = Qnil;
  VALUE result;
  VALUE *argv;
  VALUE doc;
  VALUE node_set = Qnil;
  xmlNodeSetPtr xml_node_set = NULL;
  xmlXPathObjectPtr obj;
  int i;
  nokogiriNodeSetTuple *node_set_tuple;

  assert(ctx);
  assert(ctx->context);
  assert(ctx->context->userData);
  assert(ctx->context->doc);
  assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));

  xpath_handler = (VALUE)(ctx->context->userData);

  argv = (VALUE *)calloc((size_t)nargs, sizeof(VALUE));
  for (i = 0 ; i < nargs ; ++i) {
    rb_gc_register_address(&argv[i]);
  }

  doc = DOC_RUBY_OBJECT(ctx->context->doc);

  if (nargs > 0) {
    i = nargs - 1;
    do {
      obj = valuePop(ctx);
      switch(obj->type) {
        case XPATH_STRING:
          argv[i] = NOKOGIRI_STR_NEW2(obj->stringval);
          break;
        case XPATH_BOOLEAN:
          argv[i] = obj->boolval == 1 ? Qtrue : Qfalse;
          break;
        case XPATH_NUMBER:
          argv[i] = rb_float_new(obj->floatval);
          break;
        case XPATH_NODESET:
          argv[i] = Nokogiri_wrap_xml_node_set(obj->nodesetval, doc);
          break;
        default:
          argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj));
      }
      xmlXPathFreeNodeSetList(obj);
    } while(i-- > 0);
  }

  result = rb_funcall2(
      xpath_handler,
      rb_intern((const char *)ctx->context->function),
      nargs,
      argv
  );

  for (i = 0 ; i < nargs ; ++i) {
    rb_gc_unregister_address(&argv[i]);
  }
  free(argv);

  switch(TYPE(result)) {
    case T_FLOAT:
    case T_BIGNUM:
    case T_FIXNUM:
      xmlXPathReturnNumber(ctx, NUM2DBL(result));
      break;
    case T_STRING:
      xmlXPathReturnString(
          ctx,
          (xmlChar *)xmlXPathWrapCString(StringValuePtr(result))
      );
      break;
    case T_TRUE:
      xmlXPathReturnTrue(ctx);
      break;
    case T_FALSE:
      xmlXPathReturnFalse(ctx);
      break;
    case T_NIL:
      break;
    case T_ARRAY:
      {
        VALUE args[2];
	args[0] = doc;
	args[1] = result;
        node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet);
        Data_Get_Struct(node_set, nokogiriNodeSetTuple, node_set_tuple);
	xml_node_set = node_set_tuple->node_set;
        xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
      }
      break;
    case T_DATA:
      if(rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) {
        Data_Get_Struct(result, nokogiriNodeSetTuple, node_set_tuple);
	xml_node_set = node_set_tuple->node_set;
        /* Copy the node set, otherwise it will get GC'd. */
        xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
        break;
      }
    default:
      rb_raise(rb_eRuntimeError, "Invalid return type");
  }
}
/*
 * 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;
}