nokogiri 1.0.7 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- data/History.ja.txt +14 -0
- data/History.txt +16 -0
- data/Manifest.txt +5 -0
- data/README.ja.txt +1 -1
- data/README.txt +1 -1
- data/Rakefile +5 -8
- data/ext/nokogiri/extconf.rb +46 -7
- data/ext/nokogiri/html_sax_parser.c +12 -8
- data/ext/nokogiri/xml_node.c +41 -26
- data/ext/nokogiri/xml_node_set.c +3 -0
- data/ext/nokogiri/xml_sax_parser.c +1 -0
- data/ext/nokogiri/xml_xpath_context.c +120 -4
- data/ext/nokogiri/xslt_stylesheet.c +22 -7
- data/lib/nokogiri/css.rb +1 -0
- data/lib/nokogiri/css/generated_parser.rb +142 -122
- data/lib/nokogiri/css/parser.rb +23 -19
- data/lib/nokogiri/css/parser.y +3 -1
- data/lib/nokogiri/css/selector_handler.rb +6 -0
- data/lib/nokogiri/css/xpath_visitor.rb +5 -2
- data/lib/nokogiri/html.rb +10 -0
- data/lib/nokogiri/version.rb +1 -1
- data/lib/nokogiri/xml.rb +1 -0
- data/lib/nokogiri/xml/node.rb +103 -11
- data/lib/nokogiri/xml/node_set.rb +2 -1
- data/lib/nokogiri/xml/xpath_handler.rb +6 -0
- data/lib/nokogiri/xslt.rb +17 -0
- data/test/css/test_parser.rb +6 -6
- data/test/css/test_xpath_visitor.rb +10 -0
- data/test/files/exslt.xml +8 -0
- data/test/files/exslt.xslt +35 -0
- data/test/helper.rb +2 -0
- data/test/hpricot/test_parser.rb +7 -5
- data/test/test_memory_leak.rb +2 -2
- data/test/test_xslt_transforms.rb +64 -0
- data/test/xml/test_node.rb +47 -0
- data/test/xml/test_xpath.rb +98 -0
- data/vendor/hoe.rb +22 -18
- metadata +8 -2
data/History.ja.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== HEAD
|
2
|
+
|
3
|
+
* 新しい機能
|
4
|
+
|
5
|
+
* カスタム XPath 機能はある。( 参照 Nokogiri::XML::Node#xpath )
|
6
|
+
* カスタム CSS 擬似クラスと機能はある。( 参照 Nokogiri::XML::Node#css )
|
7
|
+
* Nokogiri::XML::Node#<< は参照に子ノードを添える
|
8
|
+
|
9
|
+
* バグの修正
|
10
|
+
|
11
|
+
* mutex が CSS のキャッシュのアクセスをロックする
|
12
|
+
* GCC 3.3.5 のビルドが修正された
|
13
|
+
* XML::Node#to_xml は
|
14
|
+
|
1
15
|
=== 1.0.7
|
2
16
|
|
3
17
|
* バグの修正
|
data/History.txt
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 1.1.0
|
2
|
+
|
3
|
+
* New Features
|
4
|
+
|
5
|
+
* Custom XPath functions are now supported. See Nokogiri::XML::Node#xpath
|
6
|
+
* Custom CSS pseudo classes are now supported. See Nokogiri::XML::Node#css
|
7
|
+
* Nokogiri::XML::Node#<< will add a child to the current node
|
8
|
+
|
9
|
+
* Bugfixes
|
10
|
+
|
11
|
+
* Mutex lock on CSS cache access
|
12
|
+
* Fixed build problems with GCC 3.3.5
|
13
|
+
* XML::Node#to_xml now takes an indentation argument
|
14
|
+
* XML::Node#dup takes an optional depth argument
|
15
|
+
* XML::Node#add_previous_sibling returns new sibling node.
|
16
|
+
|
1
17
|
=== 1.0.7
|
2
18
|
|
3
19
|
* Bugfixes
|
data/Manifest.txt
CHANGED
@@ -47,6 +47,7 @@ lib/nokogiri/css/generated_tokenizer.rb
|
|
47
47
|
lib/nokogiri/css/node.rb
|
48
48
|
lib/nokogiri/css/parser.rb
|
49
49
|
lib/nokogiri/css/parser.y
|
50
|
+
lib/nokogiri/css/selector_handler.rb
|
50
51
|
lib/nokogiri/css/syntax_error.rb
|
51
52
|
lib/nokogiri/css/tokenizer.rb
|
52
53
|
lib/nokogiri/css/tokenizer.rex
|
@@ -85,6 +86,7 @@ lib/nokogiri/xml/text.rb
|
|
85
86
|
lib/nokogiri/xml/xpath.rb
|
86
87
|
lib/nokogiri/xml/xpath/syntax_error.rb
|
87
88
|
lib/nokogiri/xml/xpath_context.rb
|
89
|
+
lib/nokogiri/xml/xpath_handler.rb
|
88
90
|
lib/nokogiri/xslt.rb
|
89
91
|
lib/nokogiri/xslt/stylesheet.rb
|
90
92
|
test/css/test_nthiness.rb
|
@@ -92,6 +94,8 @@ test/css/test_parser.rb
|
|
92
94
|
test/css/test_tokenizer.rb
|
93
95
|
test/css/test_xpath_visitor.rb
|
94
96
|
test/files/dont_hurt_em_why.xml
|
97
|
+
test/files/exslt.xml
|
98
|
+
test/files/exslt.xslt
|
95
99
|
test/files/staff.xml
|
96
100
|
test/files/staff.xslt
|
97
101
|
test/files/tlm.html
|
@@ -132,4 +136,5 @@ test/xml/test_dtd.rb
|
|
132
136
|
test/xml/test_node.rb
|
133
137
|
test/xml/test_node_set.rb
|
134
138
|
test/xml/test_text.rb
|
139
|
+
test/xml/test_xpath.rb
|
135
140
|
vendor/hoe.rb
|
data/README.ja.txt
CHANGED
data/README.txt
CHANGED
@@ -22,7 +22,7 @@ correctly implemented CSS3 selector support as well as XPath support.
|
|
22
22
|
|
23
23
|
Here is a speed test:
|
24
24
|
|
25
|
-
* http://gist.github.com/
|
25
|
+
* http://gist.github.com/24605
|
26
26
|
|
27
27
|
Nokogiri also features an Hpricot compatibility layer to help ease the change
|
28
28
|
to using correct CSS and XPath.
|
data/Rakefile
CHANGED
@@ -231,9 +231,13 @@ end
|
|
231
231
|
|
232
232
|
def test_suite_cmdline
|
233
233
|
require 'find'
|
234
|
+
match = ENV['MATCH'] ? /#{ENV['MATCH']}/ : /./
|
235
|
+
|
234
236
|
files = []
|
235
237
|
Find.find("test") do |f|
|
236
|
-
|
238
|
+
basename = File.basename(f)
|
239
|
+
|
240
|
+
files << f if basename =~ /.*test.*\.rb$/ && basename =~ match
|
237
241
|
end
|
238
242
|
cmdline = "ruby -w -I.:lib:ext:test -rtest/unit -e '%w[#{files.join(' ')}].each {|f| require f}'"
|
239
243
|
end
|
@@ -328,11 +332,4 @@ unless windows
|
|
328
332
|
Rake::Task[:check_manifest].prerequisites << GENERATED_TOKENIZER
|
329
333
|
end
|
330
334
|
|
331
|
-
# Evil evil hack. Do not run tests when gem installs
|
332
|
-
if ENV['RUBYARCHDIR']
|
333
|
-
prereqs = Rake::Task[:default].prerequisites
|
334
|
-
prereqs.clear
|
335
|
-
prereqs << :build
|
336
|
-
end
|
337
|
-
|
338
335
|
# vim: syntax=Ruby
|
data/ext/nokogiri/extconf.rb
CHANGED
@@ -6,6 +6,8 @@ ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
6
6
|
LIBDIR = Config::CONFIG['libdir']
|
7
7
|
INCLUDEDIR = Config::CONFIG['includedir']
|
8
8
|
|
9
|
+
use_macports = !(defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby')
|
10
|
+
|
9
11
|
$CFLAGS << " #{ENV["CFLAGS"]}"
|
10
12
|
if Config::CONFIG['target_os'] == 'mingw32'
|
11
13
|
$CFLAGS << " -DXP_WIN -DXP_WIN32"
|
@@ -13,16 +15,36 @@ else
|
|
13
15
|
$CFLAGS << " -g -DXP_UNIX"
|
14
16
|
end
|
15
17
|
|
16
|
-
$
|
18
|
+
$LIBPATH << "/opt/local/lib" if use_macports
|
19
|
+
|
20
|
+
$CFLAGS << " -O3 -Wall -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline"
|
17
21
|
|
18
22
|
if Config::CONFIG['target_os'] == 'mingw32'
|
19
23
|
find_library('xml2', 'xmlParseDoc',
|
20
24
|
File.join(ROOT, 'cross', 'libxml2-2.7.2.win32', 'bin'))
|
21
25
|
find_library('xslt', 'xsltParseStylesheetDoc',
|
22
26
|
File.join(ROOT, 'cross', 'libxslt-1.1.24.win32', 'bin'))
|
27
|
+
find_library('exslt', 'exsltFuncRegister',
|
28
|
+
File.join(ROOT, 'cross', 'libxslt-1.1.24.win32', 'bin'))
|
23
29
|
else
|
24
|
-
find_library('xml2', 'xmlParseDoc',
|
25
|
-
|
30
|
+
find_library('xml2', 'xmlParseDoc',
|
31
|
+
LIBDIR,
|
32
|
+
'/opt/local/lib',
|
33
|
+
'/usr/local/lib',
|
34
|
+
'/usr/lib'
|
35
|
+
)
|
36
|
+
find_library('xslt', 'xsltParseStylesheetDoc',
|
37
|
+
LIBDIR,
|
38
|
+
'/opt/local/lib',
|
39
|
+
'/usr/local/lib',
|
40
|
+
'/usr/lib'
|
41
|
+
)
|
42
|
+
find_library('exslt', 'exsltFuncRegister',
|
43
|
+
LIBDIR,
|
44
|
+
'/opt/local/lib',
|
45
|
+
'/usr/local/lib',
|
46
|
+
'/usr/lib'
|
47
|
+
)
|
26
48
|
end
|
27
49
|
|
28
50
|
|
@@ -36,18 +58,35 @@ if Config::CONFIG['target_os'] == 'mingw32'
|
|
36
58
|
unless find_header('libxslt/libxslt.h', header)
|
37
59
|
abort "need libxslt"
|
38
60
|
end
|
61
|
+
unless find_header('libexslt/libexslt.h', header)
|
62
|
+
abort "need libexslt"
|
63
|
+
end
|
39
64
|
|
40
65
|
header = File.join(ROOT, 'cross', 'iconv-1.9.2.win32', 'include')
|
41
66
|
unless find_header('iconv.h', header)
|
42
67
|
abort "need iconv"
|
43
68
|
end
|
44
69
|
else
|
45
|
-
|
46
|
-
|
47
|
-
|
70
|
+
HEADER_DIRS = [
|
71
|
+
File.join(INCLUDEDIR, "libxml2"),
|
72
|
+
INCLUDEDIR,
|
73
|
+
'/usr/include/libxml2',
|
74
|
+
'/usr/local/include/libxml2'
|
75
|
+
]
|
76
|
+
|
77
|
+
[
|
78
|
+
'/opt/local/include/libxml2',
|
79
|
+
'/opt/local/include',
|
80
|
+
].each { |x| HEADER_DIRS.unshift(x) } if use_macports
|
81
|
+
|
82
|
+
unless find_header('libxml/xmlversion.h', *HEADER_DIRS)
|
48
83
|
abort "need libxml"
|
49
84
|
end
|
50
|
-
|
85
|
+
|
86
|
+
unless find_header('libxslt/xslt.h', *HEADER_DIRS)
|
87
|
+
abort "need libxslt"
|
88
|
+
end
|
89
|
+
unless find_header('libexslt/exslt.h', *HEADER_DIRS)
|
51
90
|
abort "need libxslt"
|
52
91
|
end
|
53
92
|
|
@@ -3,22 +3,26 @@
|
|
3
3
|
static VALUE native_parse_file(VALUE self, VALUE data, VALUE encoding)
|
4
4
|
{
|
5
5
|
xmlSAXHandlerPtr handler;
|
6
|
+
htmlDocPtr hdoc ;
|
6
7
|
Data_Get_Struct(self, xmlSAXHandler, handler);
|
7
|
-
htmlSAXParseFile( StringValuePtr(data),
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
hdoc = htmlSAXParseFile( StringValuePtr(data),
|
9
|
+
(const char *)StringValuePtr(encoding),
|
10
|
+
(htmlSAXHandlerPtr)handler,
|
11
|
+
(void *)self );
|
12
|
+
xmlFreeDoc(hdoc);
|
11
13
|
return data;
|
12
14
|
}
|
13
15
|
|
14
16
|
static VALUE native_parse_memory(VALUE self, VALUE data, VALUE encoding)
|
15
17
|
{
|
16
18
|
xmlSAXHandlerPtr handler;
|
19
|
+
htmlDocPtr hdoc ;
|
17
20
|
Data_Get_Struct(self, xmlSAXHandler, handler);
|
18
|
-
htmlSAXParseDoc( (xmlChar *)StringValuePtr(data),
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
hdoc = htmlSAXParseDoc( (xmlChar *)StringValuePtr(data),
|
22
|
+
(const char *)StringValuePtr(encoding),
|
23
|
+
(htmlSAXHandlerPtr)handler,
|
24
|
+
(void *)self );
|
25
|
+
xmlFreeDoc(hdoc);
|
22
26
|
return data;
|
23
27
|
}
|
24
28
|
|
data/ext/nokogiri/xml_node.c
CHANGED
@@ -70,14 +70,20 @@ static VALUE internal_subset(VALUE self)
|
|
70
70
|
* call-seq:
|
71
71
|
* dup
|
72
72
|
*
|
73
|
-
* Copy this node
|
73
|
+
* Copy this node. An optional depth may be passed in, but it defaults
|
74
|
+
* to a deep copy. 0 is a shallow copy, 1 is a deep copy.
|
74
75
|
*/
|
75
|
-
static VALUE duplicate_node(VALUE self)
|
76
|
+
static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
|
76
77
|
{
|
78
|
+
VALUE level;
|
79
|
+
|
80
|
+
if(rb_scan_args(argc, argv, "01", &level) == 0)
|
81
|
+
level = INT2NUM(1);
|
82
|
+
|
77
83
|
xmlNodePtr node, dup;
|
78
84
|
Data_Get_Struct(self, xmlNode, node);
|
79
85
|
|
80
|
-
dup = xmlCopyNode(node,
|
86
|
+
dup = xmlCopyNode(node, NUM2INT(level));
|
81
87
|
if(dup == NULL) return Qnil;
|
82
88
|
dup->doc = node->doc;
|
83
89
|
assert(node->parent);
|
@@ -150,12 +156,7 @@ static VALUE previous_sibling(VALUE self)
|
|
150
156
|
return Nokogiri_wrap_xml_node(sibling);
|
151
157
|
}
|
152
158
|
|
153
|
-
/*
|
154
|
-
* call-seq:
|
155
|
-
* replace(new_node)
|
156
|
-
*
|
157
|
-
* replace node with the new node in the document.
|
158
|
-
*/
|
159
|
+
/* :nodoc: */
|
159
160
|
static VALUE replace(VALUE self, VALUE _new_node)
|
160
161
|
{
|
161
162
|
xmlNodePtr node, new_node;
|
@@ -338,18 +339,20 @@ static VALUE get_content(VALUE self)
|
|
338
339
|
|
339
340
|
/*
|
340
341
|
* call-seq:
|
341
|
-
*
|
342
|
+
* add_child(node)
|
342
343
|
*
|
343
|
-
*
|
344
|
+
* Add +node+ as a child of this node. Returns the new child node.
|
344
345
|
*/
|
345
|
-
static VALUE
|
346
|
+
static VALUE add_child(VALUE self, VALUE child)
|
346
347
|
{
|
347
|
-
xmlNodePtr node, parent;
|
348
|
-
Data_Get_Struct(
|
349
|
-
Data_Get_Struct(
|
348
|
+
xmlNodePtr node, parent, new_child;
|
349
|
+
Data_Get_Struct(child, xmlNode, node);
|
350
|
+
Data_Get_Struct(self, xmlNode, parent);
|
350
351
|
|
351
|
-
xmlAddChild(parent, node)
|
352
|
-
|
352
|
+
if(!(new_child = xmlAddChild(parent, node)))
|
353
|
+
rb_raise(rb_eRuntimeError, "Could not add new child");
|
354
|
+
|
355
|
+
return Nokogiri_wrap_xml_node(new_child);
|
353
356
|
}
|
354
357
|
|
355
358
|
/*
|
@@ -443,13 +446,20 @@ static VALUE add_next_sibling(VALUE self, VALUE rb_node)
|
|
443
446
|
static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
|
444
447
|
{
|
445
448
|
xmlNodePtr node, new_sibling;
|
449
|
+
Check_Type(rb_node, T_DATA);
|
450
|
+
|
446
451
|
Data_Get_Struct(self, xmlNode, node);
|
447
452
|
Data_Get_Struct(rb_node, xmlNode, new_sibling);
|
448
|
-
|
453
|
+
|
454
|
+
if(!(new_sibling = xmlAddPrevSibling(node, new_sibling)))
|
455
|
+
rb_raise(rb_eRuntimeError, "Could not add previous sibling");
|
449
456
|
|
450
457
|
rb_funcall(rb_node, rb_intern("decorate!"), 0);
|
451
458
|
|
452
|
-
|
459
|
+
VALUE rb_new_sibling = Nokogiri_wrap_xml_node(new_sibling);
|
460
|
+
rb_funcall(rb_new_sibling, rb_intern("decorate!"), 0);
|
461
|
+
|
462
|
+
return rb_new_sibling;
|
453
463
|
}
|
454
464
|
|
455
465
|
/*
|
@@ -458,16 +468,21 @@ static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
|
|
458
468
|
*
|
459
469
|
* Returns this node as XML
|
460
470
|
*/
|
461
|
-
static VALUE to_xml(VALUE self)
|
471
|
+
static VALUE to_xml(int argc, VALUE *argv, VALUE self)
|
462
472
|
{
|
463
473
|
xmlBufferPtr buf ;
|
464
474
|
xmlNodePtr node ;
|
465
|
-
VALUE xml ;
|
475
|
+
VALUE xml, level;
|
476
|
+
|
477
|
+
if(rb_scan_args(argc, argv, "01", &level) == 0)
|
478
|
+
level = INT2NUM(1);
|
479
|
+
|
480
|
+
Check_Type(level, T_FIXNUM);
|
466
481
|
|
467
482
|
Data_Get_Struct(self, xmlNode, node);
|
468
483
|
|
469
484
|
buf = xmlBufferCreate() ;
|
470
|
-
xmlNodeDump(buf, node->doc, node, 2,
|
485
|
+
xmlNodeDump(buf, node->doc, node, 2, NUM2INT(level));
|
471
486
|
xml = rb_str_new2((char*)buf->content);
|
472
487
|
xmlBufferFree(buf);
|
473
488
|
return xml ;
|
@@ -646,12 +661,11 @@ void init_xml_node()
|
|
646
661
|
|
647
662
|
rb_define_method(klass, "name", get_name, 0);
|
648
663
|
rb_define_method(klass, "name=", set_name, 1);
|
649
|
-
rb_define_method(klass, "
|
664
|
+
rb_define_method(klass, "add_child", add_child, 1);
|
650
665
|
rb_define_method(klass, "parent", get_parent, 0);
|
651
666
|
rb_define_method(klass, "child", child, 0);
|
652
667
|
rb_define_method(klass, "next_sibling", next_sibling, 0);
|
653
668
|
rb_define_method(klass, "previous_sibling", previous_sibling, 0);
|
654
|
-
rb_define_method(klass, "replace", replace, 1);
|
655
669
|
rb_define_method(klass, "type", type, 0);
|
656
670
|
rb_define_method(klass, "content", get_content, 0);
|
657
671
|
rb_define_method(klass, "path", path, 0);
|
@@ -664,12 +678,13 @@ void init_xml_node()
|
|
664
678
|
rb_define_method(klass, "add_previous_sibling", add_previous_sibling, 1);
|
665
679
|
rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
|
666
680
|
rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
|
667
|
-
rb_define_method(klass, "to_xml", to_xml,
|
668
|
-
rb_define_method(klass, "dup", duplicate_node,
|
681
|
+
rb_define_method(klass, "to_xml", to_xml, -1);
|
682
|
+
rb_define_method(klass, "dup", duplicate_node, -1);
|
669
683
|
rb_define_method(klass, "unlink", unlink_node, 0);
|
670
684
|
rb_define_method(klass, "internal_subset", internal_subset, 0);
|
671
685
|
rb_define_method(klass, "pointer_id", pointer_id, 0);
|
672
686
|
|
687
|
+
rb_define_private_method(klass, "replace_with_node", replace, 1);
|
673
688
|
rb_define_private_method(klass, "native_content=", set_content, 1);
|
674
689
|
rb_define_private_method(klass, "get", get, 1);
|
675
690
|
}
|
data/ext/nokogiri/xml_node_set.c
CHANGED
@@ -28,6 +28,9 @@ static VALUE push(VALUE self, VALUE rb_node)
|
|
28
28
|
xmlNodeSetPtr node_set;
|
29
29
|
xmlNodePtr node;
|
30
30
|
|
31
|
+
if(! rb_funcall(rb_node, rb_intern("is_a?"), 1, cNokogiriXmlNode))
|
32
|
+
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
33
|
+
|
31
34
|
Data_Get_Struct(self, xmlNodeSet, node_set);
|
32
35
|
Data_Get_Struct(rb_node, xmlNode, node);
|
33
36
|
xmlXPathNodeSetAdd(node_set, node);
|
@@ -25,18 +25,132 @@ static VALUE register_ns(VALUE self, VALUE prefix, VALUE uri)
|
|
25
25
|
return self;
|
26
26
|
}
|
27
27
|
|
28
|
+
static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
|
29
|
+
{
|
30
|
+
VALUE xpath_handler = Qnil;
|
31
|
+
xmlXPathObjectPtr obj;
|
32
|
+
|
33
|
+
assert(ctx);
|
34
|
+
assert(ctx->context);
|
35
|
+
assert(ctx->context->userData);
|
36
|
+
assert(ctx->context->doc);
|
37
|
+
assert(ctx->context->doc->_private);
|
38
|
+
|
39
|
+
xpath_handler = (VALUE)(ctx->context->userData);
|
40
|
+
|
41
|
+
VALUE * argv = (VALUE *)calloc((unsigned int)nargs, sizeof(VALUE));
|
42
|
+
VALUE doc = (VALUE)ctx->context->doc->_private;
|
43
|
+
|
44
|
+
int i = nargs - 1;
|
45
|
+
do {
|
46
|
+
obj = valuePop(ctx);
|
47
|
+
switch(obj->type) {
|
48
|
+
case XPATH_STRING:
|
49
|
+
argv[i] = rb_str_new2((char *)obj->stringval);
|
50
|
+
break;
|
51
|
+
case XPATH_BOOLEAN:
|
52
|
+
argv[i] = obj->boolval == 1 ? Qtrue : Qfalse;
|
53
|
+
break;
|
54
|
+
case XPATH_NUMBER:
|
55
|
+
argv[i] = rb_float_new(obj->floatval);
|
56
|
+
break;
|
57
|
+
case XPATH_NODESET:
|
58
|
+
argv[i] = Nokogiri_wrap_xml_node_set(obj->nodesetval);
|
59
|
+
break;
|
60
|
+
default:
|
61
|
+
argv[i] = rb_str_new2((char *)xmlXPathCastToString(obj));
|
62
|
+
}
|
63
|
+
xmlXPathFreeNodeSetList(obj);
|
64
|
+
} while(i-- > 0);
|
65
|
+
|
66
|
+
VALUE result = rb_funcall2(
|
67
|
+
xpath_handler,
|
68
|
+
rb_intern((const char *)ctx->context->function),
|
69
|
+
nargs,
|
70
|
+
argv
|
71
|
+
);
|
72
|
+
free(argv);
|
73
|
+
|
74
|
+
VALUE node_set = Qnil;
|
75
|
+
xmlNodeSetPtr xml_node_set = NULL;
|
76
|
+
|
77
|
+
switch(TYPE(result)) {
|
78
|
+
case T_FLOAT:
|
79
|
+
case T_BIGNUM:
|
80
|
+
case T_FIXNUM:
|
81
|
+
xmlXPathReturnNumber(ctx, NUM2DBL(result));
|
82
|
+
break;
|
83
|
+
case T_STRING:
|
84
|
+
xmlXPathReturnString(
|
85
|
+
ctx,
|
86
|
+
xmlXPathWrapCString(StringValuePtr(result))
|
87
|
+
);
|
88
|
+
break;
|
89
|
+
case T_TRUE:
|
90
|
+
xmlXPathReturnTrue(ctx);
|
91
|
+
break;
|
92
|
+
case T_FALSE:
|
93
|
+
xmlXPathReturnFalse(ctx);
|
94
|
+
break;
|
95
|
+
case T_NIL:
|
96
|
+
break;
|
97
|
+
case T_ARRAY:
|
98
|
+
node_set = rb_funcall(
|
99
|
+
cNokogiriXmlNodeSet,
|
100
|
+
rb_intern("new"),
|
101
|
+
2,
|
102
|
+
doc,
|
103
|
+
result
|
104
|
+
);
|
105
|
+
Data_Get_Struct(node_set, xmlNodeSet, xml_node_set);
|
106
|
+
xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
|
107
|
+
break;
|
108
|
+
case T_DATA:
|
109
|
+
if(rb_funcall(result, rb_intern("is_a?"), 1, cNokogiriXmlNodeSet)) {
|
110
|
+
Data_Get_Struct(result, xmlNodeSet, xml_node_set);
|
111
|
+
// Copy the node set, otherwise it will get GC'd.
|
112
|
+
xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
default:
|
116
|
+
rb_raise(rb_eRuntimeError, "Invalid return type");
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
static xmlXPathFunction lookup( void *ctx,
|
121
|
+
const xmlChar * name,
|
122
|
+
const xmlChar* ns_uri )
|
123
|
+
{
|
124
|
+
VALUE xpath_handler = (VALUE)ctx;
|
125
|
+
if(rb_respond_to(xpath_handler, rb_intern((const char *)name)))
|
126
|
+
return ruby_funcall;
|
127
|
+
|
128
|
+
return NULL;
|
129
|
+
}
|
130
|
+
|
28
131
|
/*
|
29
132
|
* call-seq:
|
30
133
|
* evaluate(search_path)
|
31
134
|
*
|
32
135
|
* Evaluate the +search_path+ returning an XML::XPath object.
|
33
136
|
*/
|
34
|
-
static VALUE evaluate(VALUE
|
137
|
+
static VALUE evaluate(int argc, VALUE *argv, VALUE self)
|
35
138
|
{
|
139
|
+
VALUE search_path, xpath_handler;
|
36
140
|
xmlXPathContextPtr ctx;
|
37
141
|
Data_Get_Struct(self, xmlXPathContext, ctx);
|
38
142
|
|
143
|
+
if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1)
|
144
|
+
xpath_handler = Qnil;
|
145
|
+
|
39
146
|
xmlChar* query = (xmlChar *)StringValuePtr(search_path);
|
147
|
+
|
148
|
+
if(Qnil != xpath_handler) {
|
149
|
+
// FIXME: not sure if this is the correct place to shove private data.
|
150
|
+
ctx->userData = (void *)xpath_handler;
|
151
|
+
xmlXPathRegisterFuncLookup(ctx, lookup, (void *)xpath_handler);
|
152
|
+
}
|
153
|
+
|
40
154
|
xmlXPathObjectPtr xpath = xmlXPathEvalExpression(query, ctx);
|
41
155
|
if(xpath == NULL) {
|
42
156
|
VALUE xpath = rb_const_get(mNokogiriXml, rb_intern("XPath"));
|
@@ -72,8 +186,10 @@ static VALUE new(VALUE klass, VALUE nodeobj)
|
|
72
186
|
Data_Get_Struct(nodeobj, xmlNode, node);
|
73
187
|
|
74
188
|
xmlXPathContextPtr ctx = xmlXPathNewContext(node->doc);
|
75
|
-
ctx->node = node
|
76
|
-
|
189
|
+
ctx->node = node;
|
190
|
+
VALUE self = Data_Wrap_Struct(klass, 0, deallocate, ctx);
|
191
|
+
//rb_iv_set(self, "@xpath_handler", Qnil);
|
192
|
+
return self;
|
77
193
|
}
|
78
194
|
|
79
195
|
VALUE cNokogiriXmlXpathContext;
|
@@ -94,6 +210,6 @@ void init_xml_xpath_context(void)
|
|
94
210
|
cNokogiriXmlXpathContext = klass;
|
95
211
|
|
96
212
|
rb_define_singleton_method(klass, "new", new, 1);
|
97
|
-
rb_define_method(klass, "evaluate", evaluate, 1);
|
213
|
+
rb_define_method(klass, "evaluate", evaluate, -1);
|
98
214
|
rb_define_method(klass, "register_ns", register_ns, 2);
|
99
215
|
}
|