diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 14f962983db..8147491ed1e 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -15,6 +15,7 @@ * XML::NodeSet#slice gracefully handles offset+length larger than the set length. GH #200 * XML::Node#content= safely unlinks previous content. GH #203 * XML::Node#namespace= takes nil as a parameter + * XML::Node#xpath returns things other than NodeSet objects. GH #208 === 1.4.1 / 2009/12/10 diff --git a/Manifest.txt b/Manifest.txt index e90bab2fbfa..543b0232942 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -68,8 +68,6 @@ ext/nokogiri/xml_syntax_error.c ext/nokogiri/xml_syntax_error.h ext/nokogiri/xml_text.c ext/nokogiri/xml_text.h -ext/nokogiri/xml_xpath.c -ext/nokogiri/xml_xpath.h ext/nokogiri/xml_xpath_context.c ext/nokogiri/xml_xpath_context.h ext/nokogiri/xslt_stylesheet.c diff --git a/ext/nokogiri/nokogiri.c b/ext/nokogiri/nokogiri.c index fd7b9e27b84..dadbb50ae05 100644 --- a/ext/nokogiri/nokogiri.c +++ b/ext/nokogiri/nokogiri.c @@ -73,7 +73,6 @@ void Init_nokogiri() init_xml_comment(); init_xml_node_set(); init_xml_xpath_context(); - init_xml_xpath(); init_xml_sax_parser_context(); init_xml_sax_parser(); init_xml_sax_push_parser(); diff --git a/ext/nokogiri/nokogiri.h b/ext/nokogiri/nokogiri.h index 7c2b5be761a..b9087be2dc0 100644 --- a/ext/nokogiri/nokogiri.h +++ b/ext/nokogiri/nokogiri.h @@ -84,7 +84,6 @@ int is_2_6_16(void) ; #include #include #include -#include #include #include #include diff --git a/ext/nokogiri/xml_xpath.c b/ext/nokogiri/xml_xpath.c deleted file mode 100644 index 1f13abd79f7..00000000000 --- a/ext/nokogiri/xml_xpath.c +++ /dev/null @@ -1,51 +0,0 @@ -#include - -static void deallocate(xmlXPathObjectPtr xpath) -{ - NOKOGIRI_DEBUG_START(xpath); - xmlXPathFreeNodeSetList(xpath); // despite the name, this frees the xpath but not the contained node set - NOKOGIRI_DEBUG_END(xpath); -} - -VALUE Nokogiri_wrap_xml_xpath(xmlXPathObjectPtr xpath) -{ - return Data_Wrap_Struct(cNokogiriXmlXpath, 0, deallocate, xpath); -} - -/* - * call-seq: - * node_set - * - * Fetch the node set associated with this xpath context. - */ -static VALUE node_set(VALUE self) -{ - xmlXPathObjectPtr xpath; - Data_Get_Struct(self, xmlXPathObject, xpath); - - VALUE node_set = Qnil; - - if (xpath->nodesetval) - node_set = Nokogiri_wrap_xml_node_set(xpath->nodesetval, rb_iv_get(self, "@document")); - - if(NIL_P(node_set)) - node_set = Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL), rb_iv_get(self, "@document")); - - return node_set; -} - -VALUE cNokogiriXmlXpath; -void init_xml_xpath(void) -{ - VALUE module = rb_define_module("Nokogiri"); - VALUE xml = rb_define_module_under(module, "XML"); - - /* - * This class wraps an XPath object and should only be instantiated from - * XPathContext. - */ - VALUE klass = rb_define_class_under(xml, "XPath", rb_cObject); - - cNokogiriXmlXpath = klass; - rb_define_method(klass, "node_set", node_set, 0); -} diff --git a/ext/nokogiri/xml_xpath.h b/ext/nokogiri/xml_xpath.h deleted file mode 100644 index 3ddd947ce04..00000000000 --- a/ext/nokogiri/xml_xpath.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NOKOGIRI_XML_XPATH -#define NOKOGIRI_XML_XPATH - -#include - -void init_xml_xpath(); -VALUE Nokogiri_wrap_xml_xpath(xmlXPathObjectPtr xpath); - -extern VALUE cNokogiriXmlXpath; -#endif - diff --git a/ext/nokogiri/xml_xpath_context.c b/ext/nokogiri/xml_xpath_context.c index b5998fd641e..9aeb764d078 100644 --- a/ext/nokogiri/xml_xpath_context.c +++ b/ext/nokogiri/xml_xpath_context.c @@ -187,13 +187,31 @@ static VALUE evaluate(int argc, VALUE *argv, VALUE self) rb_exc_raise(Nokogiri_wrap_xml_syntax_error(klass, error)); } - VALUE xpath_object = Nokogiri_wrap_xml_xpath(xpath); + VALUE thing = Qnil; assert(ctx->doc); assert(DOC_RUBY_OBJECT_TEST(ctx->doc)); - rb_iv_set(xpath_object, "@document", DOC_RUBY_OBJECT(ctx->doc)); - return xpath_object; + switch(xpath->type) { + case XPATH_STRING: + thing = NOKOGIRI_STR_NEW2(xpath->stringval); + break; + case XPATH_NODESET: + 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)); + } + + return thing; } /* diff --git a/lib/nokogiri/xml/node.rb b/lib/nokogiri/xml/node.rb index 9fffb0c99fe..8ab13c40a0d 100644 --- a/lib/nokogiri/xml/node.rb +++ b/lib/nokogiri/xml/node.rb @@ -140,7 +140,7 @@ def xpath *paths sets = paths.map { |path| ctx = XPathContext.new(self) ctx.register_namespaces(ns) - ctx.evaluate(path, handler).node_set + ctx.evaluate(path, handler) } return sets.first if sets.length == 1 diff --git a/test/xml/test_document.rb b/test/xml/test_document.rb index b05213b882c..857be5cb74b 100644 --- a/test/xml/test_document.rb +++ b/test/xml/test_document.rb @@ -467,21 +467,21 @@ def test_find_with_namespace ctx = Nokogiri::XML::XPathContext.new(doc) ctx.register_ns 'tenderlove', 'http://tenderlovemaking.com/' - set = ctx.evaluate('//tenderlove:foo').node_set + set = ctx.evaluate('//tenderlove:foo') assert_equal 1, set.length assert_equal 'foo', set.first.name # It looks like only the URI is important: ctx = Nokogiri::XML::XPathContext.new(doc) ctx.register_ns 'america', 'http://tenderlovemaking.com/' - set = ctx.evaluate('//america:foo').node_set + set = ctx.evaluate('//america:foo') assert_equal 1, set.length assert_equal 'foo', set.first.name # Its so important that a missing slash will cause it to return nothing ctx = Nokogiri::XML::XPathContext.new(doc) ctx.register_ns 'america', 'http://tenderlovemaking.com' - set = ctx.evaluate('//america:foo').node_set + set = ctx.evaluate('//america:foo') assert_equal 0, set.length end diff --git a/test/xml/test_xpath.rb b/test/xml/test_xpath.rb index a583e5bc4ab..4f63478e142 100644 --- a/test/xml/test_xpath.rb +++ b/test/xml/test_xpath.rb @@ -34,6 +34,18 @@ def saves_node_set node_set }.new end + def test_boolean + assert_equal false, @xml.xpath('1 = 2') + end + + def test_number + assert_equal 2, @xml.xpath('1 + 1') + end + + def test_string + assert_equal 'foo', @xml.xpath('concat("fo", "o")') + end + def test_css_search_uses_custom_selectors_with_arguments set = @xml.css('employee > address:my_filter("domestic", "Yes")', @handler) assert set.length > 0