nokogiri 1.10.9 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +38 -0
  3. data/LICENSE-DEPENDENCIES.md +1632 -1022
  4. data/LICENSE.md +1 -1
  5. data/README.md +190 -95
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +34 -66
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +909 -422
  10. data/ext/nokogiri/gumbo.c +610 -0
  11. data/ext/nokogiri/html4_document.c +171 -0
  12. data/ext/nokogiri/html4_element_description.c +299 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser.c +40 -0
  15. data/ext/nokogiri/html4_sax_parser_context.c +98 -0
  16. data/ext/nokogiri/html4_sax_push_parser.c +96 -0
  17. data/ext/nokogiri/libxml2_polyfill.c +114 -0
  18. data/ext/nokogiri/nokogiri.c +258 -105
  19. data/ext/nokogiri/nokogiri.h +207 -90
  20. data/ext/nokogiri/test_global_handlers.c +40 -0
  21. data/ext/nokogiri/xml_attr.c +18 -18
  22. data/ext/nokogiri/xml_attribute_decl.c +22 -22
  23. data/ext/nokogiri/xml_cdata.c +33 -33
  24. data/ext/nokogiri/xml_comment.c +19 -31
  25. data/ext/nokogiri/xml_document.c +499 -323
  26. data/ext/nokogiri/xml_document_fragment.c +17 -36
  27. data/ext/nokogiri/xml_dtd.c +65 -59
  28. data/ext/nokogiri/xml_element_content.c +63 -55
  29. data/ext/nokogiri/xml_element_decl.c +31 -31
  30. data/ext/nokogiri/xml_encoding_handler.c +54 -21
  31. data/ext/nokogiri/xml_entity_decl.c +37 -35
  32. data/ext/nokogiri/xml_entity_reference.c +17 -19
  33. data/ext/nokogiri/xml_namespace.c +131 -61
  34. data/ext/nokogiri/xml_node.c +1429 -723
  35. data/ext/nokogiri/xml_node_set.c +257 -225
  36. data/ext/nokogiri/xml_processing_instruction.c +18 -20
  37. data/ext/nokogiri/xml_reader.c +340 -231
  38. data/ext/nokogiri/xml_relax_ng.c +87 -99
  39. data/ext/nokogiri/xml_sax_parser.c +269 -176
  40. data/ext/nokogiri/xml_sax_parser_context.c +286 -152
  41. data/ext/nokogiri/xml_sax_push_parser.c +111 -64
  42. data/ext/nokogiri/xml_schema.c +132 -140
  43. data/ext/nokogiri/xml_syntax_error.c +52 -23
  44. data/ext/nokogiri/xml_text.c +37 -30
  45. data/ext/nokogiri/xml_xpath_context.c +373 -185
  46. data/ext/nokogiri/xslt_stylesheet.c +342 -191
  47. data/gumbo-parser/CHANGES.md +63 -0
  48. data/gumbo-parser/Makefile +129 -0
  49. data/gumbo-parser/THANKS +27 -0
  50. data/gumbo-parser/src/Makefile +34 -0
  51. data/gumbo-parser/src/README.md +41 -0
  52. data/gumbo-parser/src/ascii.c +75 -0
  53. data/gumbo-parser/src/ascii.h +115 -0
  54. data/gumbo-parser/src/attribute.c +42 -0
  55. data/gumbo-parser/src/attribute.h +17 -0
  56. data/gumbo-parser/src/char_ref.c +22225 -0
  57. data/gumbo-parser/src/char_ref.h +29 -0
  58. data/gumbo-parser/src/char_ref.rl +2154 -0
  59. data/gumbo-parser/src/error.c +658 -0
  60. data/gumbo-parser/src/error.h +152 -0
  61. data/gumbo-parser/src/foreign_attrs.c +103 -0
  62. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  63. data/gumbo-parser/src/insertion_mode.h +33 -0
  64. data/gumbo-parser/src/macros.h +91 -0
  65. data/gumbo-parser/src/nokogiri_gumbo.h +953 -0
  66. data/gumbo-parser/src/parser.c +4932 -0
  67. data/gumbo-parser/src/parser.h +41 -0
  68. data/gumbo-parser/src/replacement.h +33 -0
  69. data/gumbo-parser/src/string_buffer.c +103 -0
  70. data/gumbo-parser/src/string_buffer.h +68 -0
  71. data/gumbo-parser/src/string_piece.c +48 -0
  72. data/gumbo-parser/src/svg_attrs.c +174 -0
  73. data/gumbo-parser/src/svg_attrs.gperf +77 -0
  74. data/gumbo-parser/src/svg_tags.c +137 -0
  75. data/gumbo-parser/src/svg_tags.gperf +55 -0
  76. data/gumbo-parser/src/tag.c +223 -0
  77. data/gumbo-parser/src/tag_lookup.c +382 -0
  78. data/gumbo-parser/src/tag_lookup.gperf +170 -0
  79. data/gumbo-parser/src/tag_lookup.h +13 -0
  80. data/gumbo-parser/src/token_buffer.c +79 -0
  81. data/gumbo-parser/src/token_buffer.h +71 -0
  82. data/gumbo-parser/src/token_type.h +17 -0
  83. data/gumbo-parser/src/tokenizer.c +3464 -0
  84. data/gumbo-parser/src/tokenizer.h +112 -0
  85. data/gumbo-parser/src/tokenizer_states.h +339 -0
  86. data/gumbo-parser/src/utf8.c +245 -0
  87. data/gumbo-parser/src/utf8.h +164 -0
  88. data/gumbo-parser/src/util.c +66 -0
  89. data/gumbo-parser/src/util.h +34 -0
  90. data/gumbo-parser/src/vector.c +111 -0
  91. data/gumbo-parser/src/vector.h +45 -0
  92. data/lib/nokogiri/class_resolver.rb +67 -0
  93. data/lib/nokogiri/css/node.rb +14 -8
  94. data/lib/nokogiri/css/parser.rb +399 -377
  95. data/lib/nokogiri/css/parser.y +250 -245
  96. data/lib/nokogiri/css/parser_extras.rb +16 -71
  97. data/lib/nokogiri/css/selector_cache.rb +38 -0
  98. data/lib/nokogiri/css/syntax_error.rb +3 -1
  99. data/lib/nokogiri/css/tokenizer.rb +7 -5
  100. data/lib/nokogiri/css/tokenizer.rex +11 -9
  101. data/lib/nokogiri/css/xpath_visitor.rb +242 -96
  102. data/lib/nokogiri/css.rb +122 -17
  103. data/lib/nokogiri/decorators/slop.rb +11 -11
  104. data/lib/nokogiri/encoding_handler.rb +57 -0
  105. data/lib/nokogiri/extension.rb +32 -0
  106. data/lib/nokogiri/gumbo.rb +15 -0
  107. data/lib/nokogiri/html.rb +38 -27
  108. data/lib/nokogiri/{html → html4}/builder.rb +4 -2
  109. data/lib/nokogiri/html4/document.rb +235 -0
  110. data/lib/nokogiri/html4/document_fragment.rb +166 -0
  111. data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
  112. data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
  113. data/lib/nokogiri/html4/encoding_reader.rb +121 -0
  114. data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
  115. data/lib/nokogiri/html4/sax/parser.rb +48 -0
  116. data/lib/nokogiri/html4/sax/parser_context.rb +15 -0
  117. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
  118. data/lib/nokogiri/html4.rb +42 -0
  119. data/lib/nokogiri/html5/builder.rb +40 -0
  120. data/lib/nokogiri/html5/document.rb +199 -0
  121. data/lib/nokogiri/html5/document_fragment.rb +200 -0
  122. data/lib/nokogiri/html5/node.rb +103 -0
  123. data/lib/nokogiri/html5.rb +368 -0
  124. data/lib/nokogiri/jruby/dependencies.rb +3 -0
  125. data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
  126. data/lib/nokogiri/syntax_error.rb +2 -0
  127. data/lib/nokogiri/version/constant.rb +6 -0
  128. data/lib/nokogiri/version/info.rb +224 -0
  129. data/lib/nokogiri/version.rb +3 -108
  130. data/lib/nokogiri/xml/attr.rb +55 -3
  131. data/lib/nokogiri/xml/attribute_decl.rb +6 -2
  132. data/lib/nokogiri/xml/builder.rb +83 -35
  133. data/lib/nokogiri/xml/cdata.rb +3 -1
  134. data/lib/nokogiri/xml/character_data.rb +2 -0
  135. data/lib/nokogiri/xml/document.rb +359 -130
  136. data/lib/nokogiri/xml/document_fragment.rb +170 -54
  137. data/lib/nokogiri/xml/dtd.rb +4 -2
  138. data/lib/nokogiri/xml/element_content.rb +12 -2
  139. data/lib/nokogiri/xml/element_decl.rb +6 -2
  140. data/lib/nokogiri/xml/entity_decl.rb +7 -3
  141. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  142. data/lib/nokogiri/xml/namespace.rb +44 -0
  143. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  144. data/lib/nokogiri/xml/node.rb +1168 -420
  145. data/lib/nokogiri/xml/node_set.rb +145 -67
  146. data/lib/nokogiri/xml/notation.rb +13 -0
  147. data/lib/nokogiri/xml/parse_options.rb +145 -52
  148. data/lib/nokogiri/xml/pp/character_data.rb +9 -6
  149. data/lib/nokogiri/xml/pp/node.rb +47 -30
  150. data/lib/nokogiri/xml/pp.rb +4 -2
  151. data/lib/nokogiri/xml/processing_instruction.rb +4 -1
  152. data/lib/nokogiri/xml/reader.rb +68 -41
  153. data/lib/nokogiri/xml/relax_ng.rb +60 -17
  154. data/lib/nokogiri/xml/sax/document.rb +198 -111
  155. data/lib/nokogiri/xml/sax/parser.rb +144 -67
  156. data/lib/nokogiri/xml/sax/parser_context.rb +119 -6
  157. data/lib/nokogiri/xml/sax/push_parser.rb +9 -5
  158. data/lib/nokogiri/xml/sax.rb +54 -4
  159. data/lib/nokogiri/xml/schema.rb +116 -39
  160. data/lib/nokogiri/xml/searchable.rb +139 -95
  161. data/lib/nokogiri/xml/syntax_error.rb +29 -5
  162. data/lib/nokogiri/xml/text.rb +2 -0
  163. data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
  164. data/lib/nokogiri/xml/xpath.rb +15 -4
  165. data/lib/nokogiri/xml/xpath_context.rb +15 -4
  166. data/lib/nokogiri/xml.rb +45 -55
  167. data/lib/nokogiri/xslt/stylesheet.rb +32 -8
  168. data/lib/nokogiri/xslt.rb +103 -30
  169. data/lib/nokogiri.rb +59 -75
  170. data/lib/xsd/xmlparser/nokogiri.rb +32 -29
  171. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  172. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  173. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  174. data/patches/libxml2/0019-xpath-Use-separate-static-hash-table-for-standard-fu.patch +244 -0
  175. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  176. data/ports/archives/libxml2-2.13.6.tar.xz +0 -0
  177. data/ports/archives/libxslt-1.1.42.tar.xz +0 -0
  178. metadata +123 -295
  179. data/ext/nokogiri/html_document.c +0 -170
  180. data/ext/nokogiri/html_document.h +0 -10
  181. data/ext/nokogiri/html_element_description.c +0 -279
  182. data/ext/nokogiri/html_element_description.h +0 -10
  183. data/ext/nokogiri/html_entity_lookup.c +0 -32
  184. data/ext/nokogiri/html_entity_lookup.h +0 -8
  185. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  186. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  187. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  188. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  189. data/ext/nokogiri/xml_attr.h +0 -9
  190. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  191. data/ext/nokogiri/xml_cdata.h +0 -9
  192. data/ext/nokogiri/xml_comment.h +0 -9
  193. data/ext/nokogiri/xml_document.h +0 -23
  194. data/ext/nokogiri/xml_document_fragment.h +0 -10
  195. data/ext/nokogiri/xml_dtd.h +0 -10
  196. data/ext/nokogiri/xml_element_content.h +0 -10
  197. data/ext/nokogiri/xml_element_decl.h +0 -9
  198. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  199. data/ext/nokogiri/xml_entity_decl.h +0 -10
  200. data/ext/nokogiri/xml_entity_reference.h +0 -9
  201. data/ext/nokogiri/xml_io.c +0 -61
  202. data/ext/nokogiri/xml_io.h +0 -11
  203. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  204. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  205. data/ext/nokogiri/xml_namespace.h +0 -14
  206. data/ext/nokogiri/xml_node.h +0 -13
  207. data/ext/nokogiri/xml_node_set.h +0 -12
  208. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  209. data/ext/nokogiri/xml_reader.h +0 -10
  210. data/ext/nokogiri/xml_relax_ng.h +0 -9
  211. data/ext/nokogiri/xml_sax_parser.h +0 -39
  212. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  213. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  214. data/ext/nokogiri/xml_schema.h +0 -9
  215. data/ext/nokogiri/xml_syntax_error.h +0 -13
  216. data/ext/nokogiri/xml_text.h +0 -9
  217. data/ext/nokogiri/xml_xpath_context.h +0 -10
  218. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  219. data/lib/nokogiri/html/document.rb +0 -335
  220. data/lib/nokogiri/html/document_fragment.rb +0 -49
  221. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  222. data/lib/nokogiri/html/sax/parser.rb +0 -62
  223. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  224. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  225. data/patches/libxml2/0004-libxml2.la-is-in-top_builddir.patch +0 -25
  226. data/patches/libxml2/0005-Fix-infinite-loop-in-xmlStringLenDecodeEntities.patch +0 -32
  227. data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
  228. data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
  229. /data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
  230. /data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
@@ -1,298 +1,486 @@
1
- #include <xml_xpath_context.h>
1
+ #include <nokogiri.h>
2
2
 
3
- int vasprintf (char **strp, const char *fmt, va_list ap);
3
+ VALUE cNokogiriXmlXpathContext;
4
+
5
+ /*
6
+ * these constants have matching declarations in
7
+ * ext/java/nokogiri/internals/NokogiriNamespaceContext.java
8
+ */
9
+ static const xmlChar *NOKOGIRI_PREFIX = (const xmlChar *)"nokogiri";
10
+ static const xmlChar *NOKOGIRI_URI = (const xmlChar *)"http://www.nokogiri.org/default_ns/ruby/extensions_functions";
11
+ static const xmlChar *NOKOGIRI_BUILTIN_PREFIX = (const xmlChar *)"nokogiri-builtin";
12
+ static const xmlChar *NOKOGIRI_BUILTIN_URI = (const xmlChar *)"https://www.nokogiri.org/default_ns/ruby/builtins";
4
13
 
5
- static void deallocate(xmlXPathContextPtr ctx)
14
+ static void
15
+ _noko_xml_xpath_context_dfree(void *data)
6
16
  {
7
- NOKOGIRI_DEBUG_START(ctx);
8
- xmlXPathFreeContext(ctx);
9
- NOKOGIRI_DEBUG_END(ctx);
17
+ xmlXPathContextPtr c_context = data;
18
+ xmlXPathFreeContext(c_context);
10
19
  }
11
20
 
21
+ static const rb_data_type_t _noko_xml_xpath_context_type = {
22
+ .wrap_struct_name = "xmlXPathContext",
23
+ .function = {
24
+ .dfree = _noko_xml_xpath_context_dfree,
25
+ },
26
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
27
+ };
28
+
29
+ /* find a CSS class in an HTML element's `class` attribute */
30
+ static const xmlChar *
31
+ _noko_xml_xpath_context__css_class(const xmlChar *str, const xmlChar *val)
32
+ {
33
+ int val_len;
34
+
35
+ if (str == NULL) { return (NULL); }
36
+ if (val == NULL) { return (NULL); }
37
+
38
+ val_len = xmlStrlen(val);
39
+ if (val_len == 0) { return (str); }
40
+
41
+ while (*str != 0) {
42
+ if ((*str == *val) && !xmlStrncmp(str, val, val_len)) {
43
+ const xmlChar *next_byte = str + val_len;
44
+
45
+ /* only match if the next byte is whitespace or end of string */
46
+ if ((*next_byte == 0) || (IS_BLANK_CH(*next_byte))) {
47
+ return ((const xmlChar *)str);
48
+ }
49
+ }
50
+
51
+ /* advance str to whitespace */
52
+ while ((*str != 0) && !IS_BLANK_CH(*str)) {
53
+ str++;
54
+ }
55
+
56
+ /* advance str to start of next word or end of string */
57
+ while ((*str != 0) && IS_BLANK_CH(*str)) {
58
+ str++;
59
+ }
60
+ }
61
+
62
+ return (NULL);
63
+ }
64
+
65
+ /* xmlXPathFunction to wrap _noko_xml_xpath_context__css_class() */
66
+ static void
67
+ noko_xml_xpath_context_xpath_func_css_class(xmlXPathParserContextPtr ctxt, int nargs)
68
+ {
69
+ xmlXPathObjectPtr hay, needle;
70
+
71
+ CHECK_ARITY(2);
72
+
73
+ CAST_TO_STRING;
74
+ needle = valuePop(ctxt);
75
+ if ((needle == NULL) || (needle->type != XPATH_STRING)) {
76
+ xmlXPathFreeObject(needle);
77
+ XP_ERROR(XPATH_INVALID_TYPE);
78
+ }
79
+
80
+ CAST_TO_STRING;
81
+ hay = valuePop(ctxt);
82
+ if ((hay == NULL) || (hay->type != XPATH_STRING)) {
83
+ xmlXPathFreeObject(hay);
84
+ xmlXPathFreeObject(needle);
85
+ XP_ERROR(XPATH_INVALID_TYPE);
86
+ }
87
+
88
+ if (_noko_xml_xpath_context__css_class(hay->stringval, needle->stringval)) {
89
+ valuePush(ctxt, xmlXPathNewBoolean(1));
90
+ } else {
91
+ valuePush(ctxt, xmlXPathNewBoolean(0));
92
+ }
93
+
94
+ xmlXPathFreeObject(hay);
95
+ xmlXPathFreeObject(needle);
96
+ }
97
+
98
+
99
+ /* xmlXPathFunction to select nodes whose local name matches, for HTML5 CSS queries that should
100
+ * ignore namespaces */
101
+ static void
102
+ noko_xml_xpath_context_xpath_func_local_name_is(xmlXPathParserContextPtr ctxt, int nargs)
103
+ {
104
+ xmlXPathObjectPtr element_name;
105
+
106
+ assert(ctxt->context->node);
107
+
108
+ CHECK_ARITY(1);
109
+ CAST_TO_STRING;
110
+ CHECK_TYPE(XPATH_STRING);
111
+ element_name = valuePop(ctxt);
112
+
113
+ valuePush(
114
+ ctxt,
115
+ xmlXPathNewBoolean(xmlStrEqual(ctxt->context->node->name, element_name->stringval))
116
+ );
117
+
118
+ xmlXPathFreeObject(element_name);
119
+ }
120
+
121
+
12
122
  /*
13
123
  * call-seq:
14
- * register_ns(prefix, uri)
124
+ * register_ns(prefix, uri) → Nokogiri::XML::XPathContext
15
125
  *
16
- * Register the namespace with +prefix+ and +uri+.
126
+ * Register the namespace with +prefix+ and +uri+ for use in future queries.
127
+ * Passing a uri of +nil+ will unregister the namespace.
128
+ *
129
+ * [Returns] +self+
17
130
  */
18
- static VALUE register_ns(VALUE self, VALUE prefix, VALUE uri)
131
+ static VALUE
132
+ noko_xml_xpath_context_register_ns(VALUE rb_context, VALUE prefix, VALUE uri)
19
133
  {
20
- xmlXPathContextPtr ctx;
21
- Data_Get_Struct(self, xmlXPathContext, ctx);
134
+ xmlXPathContextPtr c_context;
135
+ const xmlChar *ns_uri;
22
136
 
23
- xmlXPathRegisterNs( ctx,
24
- (const xmlChar *)StringValueCStr(prefix),
25
- (const xmlChar *)StringValueCStr(uri)
26
- );
27
- return self;
137
+ TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context);
138
+
139
+ if (NIL_P(uri)) {
140
+ ns_uri = NULL;
141
+ } else {
142
+ ns_uri = (const xmlChar *)StringValueCStr(uri);
143
+ }
144
+
145
+ xmlXPathRegisterNs(c_context, (const xmlChar *)StringValueCStr(prefix), ns_uri);
146
+
147
+ return rb_context;
28
148
  }
29
149
 
30
150
  /*
31
151
  * call-seq:
32
- * register_variable(name, value)
152
+ * register_variable(name, value) → Nokogiri::XML::XPathContext
153
+ *
154
+ * Register the variable +name+ with +value+ for use in future queries.
155
+ * Passing a value of +nil+ will unregister the variable.
33
156
  *
34
- * Register the variable +name+ with +value+.
157
+ * [Returns] +self+
35
158
  */
36
- static VALUE register_variable(VALUE self, VALUE name, VALUE value)
159
+ static VALUE
160
+ noko_xml_xpath_context_register_variable(VALUE rb_context, VALUE name, VALUE value)
37
161
  {
38
- xmlXPathContextPtr ctx;
39
- xmlXPathObjectPtr xmlValue;
40
- Data_Get_Struct(self, xmlXPathContext, ctx);
162
+ xmlXPathContextPtr c_context;
163
+ xmlXPathObjectPtr xmlValue;
41
164
 
42
- xmlValue = xmlXPathNewCString(StringValueCStr(value));
165
+ TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context);
43
166
 
44
- xmlXPathRegisterVariable( ctx,
45
- (const xmlChar *)StringValueCStr(name),
46
- xmlValue
47
- );
167
+ if (NIL_P(value)) {
168
+ xmlValue = NULL;
169
+ } else {
170
+ xmlValue = xmlXPathNewCString(StringValueCStr(value));
171
+ }
172
+
173
+ xmlXPathRegisterVariable(c_context, (const xmlChar *)StringValueCStr(name), xmlValue);
48
174
 
49
- return self;
175
+ return rb_context;
50
176
  }
51
177
 
52
- void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, const char* function_name)
178
+
179
+ /*
180
+ * convert an XPath object into a Ruby object of the appropriate type.
181
+ * returns Qundef if no conversion was possible.
182
+ */
183
+ static VALUE
184
+ _noko_xml_xpath_context__xpath2ruby(xmlXPathObjectPtr c_xpath_object, xmlXPathContextPtr c_context)
53
185
  {
54
- int i;
55
- VALUE result, doc;
186
+ VALUE rb_retval;
187
+
188
+ assert(c_context->doc);
189
+ assert(DOC_RUBY_OBJECT_TEST(c_context->doc));
190
+
191
+ switch (c_xpath_object->type) {
192
+ case XPATH_STRING:
193
+ rb_retval = NOKOGIRI_STR_NEW2(c_xpath_object->stringval);
194
+ xmlFree(c_xpath_object->stringval);
195
+ return rb_retval;
196
+
197
+ case XPATH_NODESET:
198
+ return noko_xml_node_set_wrap(
199
+ c_xpath_object->nodesetval,
200
+ DOC_RUBY_OBJECT(c_context->doc)
201
+ );
202
+
203
+ case XPATH_NUMBER:
204
+ return rb_float_new(c_xpath_object->floatval);
205
+
206
+ case XPATH_BOOLEAN:
207
+ return (c_xpath_object->boolval == 1) ? Qtrue : Qfalse;
208
+
209
+ default:
210
+ return Qundef;
211
+ }
212
+ }
213
+
214
+ void
215
+ Nokogiri_marshal_xpath_funcall_and_return_values(
216
+ xmlXPathParserContextPtr ctxt,
217
+ int argc,
218
+ VALUE rb_xpath_handler,
219
+ const char *method_name
220
+ )
221
+ {
222
+ VALUE rb_retval;
56
223
  VALUE *argv;
57
- VALUE node_set = Qnil;
58
- xmlNodeSetPtr xml_node_set = NULL;
59
- xmlXPathObjectPtr obj;
224
+ VALUE rb_node_set = Qnil;
225
+ xmlNodeSetPtr c_node_set = NULL;
226
+ xmlXPathObjectPtr c_xpath_object;
60
227
 
61
- assert(ctx->context->doc);
62
- assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));
228
+ assert(ctxt->context->doc);
229
+ assert(DOC_RUBY_OBJECT_TEST(ctxt->context->doc));
63
230
 
64
- argv = (VALUE *)calloc((size_t)nargs, sizeof(VALUE));
65
- for (i = 0 ; i < nargs ; ++i) {
66
- rb_gc_register_address(&argv[i]);
231
+ argv = (VALUE *)ruby_xcalloc((size_t)argc, sizeof(VALUE));
232
+ for (int j = 0 ; j < argc ; ++j) {
233
+ rb_gc_register_address(&argv[j]);
67
234
  }
68
235
 
69
- doc = DOC_RUBY_OBJECT(ctx->context->doc);
70
-
71
- if (nargs > 0) {
72
- i = nargs - 1;
73
- do {
74
- obj = valuePop(ctx);
75
- switch(obj->type) {
76
- case XPATH_STRING:
77
- argv[i] = NOKOGIRI_STR_NEW2(obj->stringval);
78
- break;
79
- case XPATH_BOOLEAN:
80
- argv[i] = obj->boolval == 1 ? Qtrue : Qfalse;
81
- break;
82
- case XPATH_NUMBER:
83
- argv[i] = rb_float_new(obj->floatval);
84
- break;
85
- case XPATH_NODESET:
86
- argv[i] = Nokogiri_wrap_xml_node_set(obj->nodesetval, doc);
87
- break;
88
- default:
89
- argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj));
90
- }
91
- xmlXPathFreeNodeSetList(obj);
92
- } while(i-- > 0);
236
+ for (int j = argc - 1 ; j >= 0 ; --j) {
237
+ c_xpath_object = valuePop(ctxt);
238
+ argv[j] = _noko_xml_xpath_context__xpath2ruby(c_xpath_object, ctxt->context);
239
+ if (argv[j] == Qundef) {
240
+ argv[j] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(c_xpath_object));
241
+ }
242
+ xmlXPathFreeNodeSetList(c_xpath_object);
93
243
  }
94
244
 
95
- result = rb_funcall2(handler, rb_intern((const char*)function_name), nargs, argv);
245
+ rb_retval = rb_funcall2(
246
+ rb_xpath_handler,
247
+ rb_intern((const char *)method_name),
248
+ argc,
249
+ argv
250
+ );
96
251
 
97
- for (i = 0 ; i < nargs ; ++i) {
98
- rb_gc_unregister_address(&argv[i]);
252
+ for (int j = 0 ; j < argc ; ++j) {
253
+ rb_gc_unregister_address(&argv[j]);
99
254
  }
100
- free(argv);
255
+ ruby_xfree(argv);
101
256
 
102
- switch(TYPE(result)) {
257
+ switch (TYPE(rb_retval)) {
103
258
  case T_FLOAT:
104
259
  case T_BIGNUM:
105
260
  case T_FIXNUM:
106
- xmlXPathReturnNumber(ctx, NUM2DBL(result));
261
+ xmlXPathReturnNumber(ctxt, NUM2DBL(rb_retval));
107
262
  break;
108
263
  case T_STRING:
109
- xmlXPathReturnString(
110
- ctx,
111
- xmlCharStrdup(StringValueCStr(result))
112
- );
264
+ xmlXPathReturnString(ctxt, xmlCharStrdup(StringValueCStr(rb_retval)));
113
265
  break;
114
266
  case T_TRUE:
115
- xmlXPathReturnTrue(ctx);
267
+ xmlXPathReturnTrue(ctxt);
116
268
  break;
117
269
  case T_FALSE:
118
- xmlXPathReturnFalse(ctx);
270
+ xmlXPathReturnFalse(ctxt);
119
271
  break;
120
272
  case T_NIL:
121
273
  break;
122
- case T_ARRAY:
123
- {
124
- VALUE args[2];
125
- args[0] = doc;
126
- args[1] = result;
127
- node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet);
128
- Data_Get_Struct(node_set, xmlNodeSet, xml_node_set);
129
- xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
130
- }
274
+ case T_ARRAY: {
275
+ VALUE construct_args[2] = { DOC_RUBY_OBJECT(ctxt->context->doc), rb_retval };
276
+ rb_node_set = rb_class_new_instance(2, construct_args, cNokogiriXmlNodeSet);
277
+ c_node_set = noko_xml_node_set_unwrap(rb_node_set);
278
+ xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set));
279
+ }
131
280
  break;
132
281
  case T_DATA:
133
- if(rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) {
134
- Data_Get_Struct(result, xmlNodeSet, xml_node_set);
282
+ if (rb_obj_is_kind_of(rb_retval, cNokogiriXmlNodeSet)) {
283
+ c_node_set = noko_xml_node_set_unwrap(rb_retval);
135
284
  /* Copy the node set, otherwise it will get GC'd. */
136
- xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
285
+ xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set));
137
286
  break;
138
287
  }
139
288
  default:
140
289
  rb_raise(rb_eRuntimeError, "Invalid return type");
141
- }
290
+ }
142
291
  }
143
292
 
144
- static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
293
+ static void
294
+ _noko_xml_xpath_context__handler_invoker(xmlXPathParserContextPtr ctxt, int argc)
145
295
  {
146
- VALUE handler = Qnil;
147
- const char *function = NULL ;
148
-
149
- assert(ctx);
150
- assert(ctx->context);
151
- assert(ctx->context->userData);
152
- assert(ctx->context->function);
153
-
154
- handler = (VALUE)(ctx->context->userData);
155
- function = (const char*)(ctx->context->function);
156
-
157
- Nokogiri_marshal_xpath_funcall_and_return_values(ctx, nargs, handler, function);
296
+ VALUE rb_xpath_handler = Qnil;
297
+ const char *method_name = NULL ;
298
+
299
+ assert(ctxt);
300
+ assert(ctxt->context);
301
+ assert(ctxt->context->userData);
302
+ assert(ctxt->context->function);
303
+
304
+ rb_xpath_handler = (VALUE)(ctxt->context->userData);
305
+ method_name = (const char *)(ctxt->context->function);
306
+
307
+ Nokogiri_marshal_xpath_funcall_and_return_values(
308
+ ctxt,
309
+ argc,
310
+ rb_xpath_handler,
311
+ method_name
312
+ );
158
313
  }
159
314
 
160
- static xmlXPathFunction lookup( void *ctx,
161
- const xmlChar * name,
162
- const xmlChar* ns_uri )
315
+ static xmlXPathFunction
316
+ _noko_xml_xpath_context_handler_lookup(void *data, const xmlChar *c_name, const xmlChar *c_ns_uri)
163
317
  {
164
- VALUE xpath_handler = (VALUE)ctx;
165
- if(rb_respond_to(xpath_handler, rb_intern((const char *)name)))
166
- return ruby_funcall;
318
+ VALUE rb_handler = (VALUE)data;
319
+ if (rb_respond_to(rb_handler, rb_intern((const char *)c_name))) {
320
+ if (c_ns_uri == NULL) {
321
+ NOKO_WARN_DEPRECATION("A custom XPath or CSS handler function named '%s' is being invoked without a namespace. Please update your query to reference this function as 'nokogiri:%s'. Invoking custom handler functions without a namespace is deprecated and will become an error in Nokogiri v1.17.0.",
322
+ c_name, c_name); // TODO deprecated in v1.15.0, remove in v1.19.0
323
+ }
324
+ return _noko_xml_xpath_context__handler_invoker;
325
+ }
167
326
 
168
327
  return NULL;
169
328
  }
170
329
 
171
- NORETURN(static void xpath_generic_exception_handler(void * ctx, const char *msg, ...));
172
- static void xpath_generic_exception_handler(void * ctx, const char *msg, ...)
330
+ PRINTFLIKE_DECL(2, 3)
331
+ static void
332
+ _noko_xml_xpath_context__generic_exception_pusher(void *data, const char *msg, ...)
173
333
  {
174
- char * message;
334
+ VALUE rb_errors = (VALUE)data;
335
+ VALUE rb_message;
336
+ VALUE rb_exception;
175
337
 
338
+ Check_Type(rb_errors, T_ARRAY);
339
+
340
+ #ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES
341
+ /* It is not currently possible to pass var args from native
342
+ functions to sulong, so we work around the issue here. */
343
+ rb_message = rb_sprintf("_noko_xml_xpath_context__generic_exception_pusher: %s", msg);
344
+ #else
176
345
  va_list args;
177
346
  va_start(args, msg);
178
- vasprintf(&message, msg, args);
347
+ rb_message = rb_vsprintf(msg, args);
179
348
  va_end(args);
349
+ #endif
180
350
 
181
- rb_raise(rb_eRuntimeError, "%s", message);
351
+ rb_exception = rb_exc_new_str(cNokogiriXmlXpathSyntaxError, rb_message);
352
+ rb_ary_push(rb_errors, rb_exception);
182
353
  }
183
354
 
184
355
  /*
185
356
  * call-seq:
186
- * evaluate(search_path, handler = nil)
357
+ * evaluate(search_path, handler = nil) → Object
358
+ *
359
+ * Evaluate the +search_path+ query.
187
360
  *
188
- * Evaluate the +search_path+ returning an XML::XPath object.
361
+ * [Returns] an object of the appropriate type for the query, which could be +NodeSet+, a +String+,
362
+ * a +Float+, or a boolean.
189
363
  */
190
- static VALUE evaluate(int argc, VALUE *argv, VALUE self)
364
+ static VALUE
365
+ noko_xml_xpath_context_evaluate(int argc, VALUE *argv, VALUE rb_context)
191
366
  {
192
- VALUE search_path, xpath_handler;
193
- VALUE thing = Qnil;
194
- xmlXPathContextPtr ctx;
195
- xmlXPathObjectPtr xpath;
196
- xmlChar *query;
367
+ xmlXPathContextPtr c_context;
368
+ VALUE rb_expression = Qnil;
369
+ VALUE rb_function_lookup_handler = Qnil;
370
+ xmlChar *c_expression_str = NULL;
371
+ VALUE rb_errors = rb_ary_new();
372
+ xmlXPathObjectPtr c_xpath_object;
373
+ VALUE rb_xpath_object = Qnil;
197
374
 
198
- Data_Get_Struct(self, xmlXPathContext, ctx);
375
+ TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context);
199
376
 
200
- if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1)
201
- xpath_handler = Qnil;
377
+ rb_scan_args(argc, argv, "11", &rb_expression, &rb_function_lookup_handler);
202
378
 
203
- query = (xmlChar *)StringValueCStr(search_path);
379
+ c_expression_str = (xmlChar *)StringValueCStr(rb_expression);
204
380
 
205
- if(Qnil != xpath_handler) {
381
+ if (Qnil != rb_function_lookup_handler) {
206
382
  /* FIXME: not sure if this is the correct place to shove private data. */
207
- ctx->userData = (void *)xpath_handler;
208
- xmlXPathRegisterFuncLookup(ctx, lookup, (void *)xpath_handler);
383
+ c_context->userData = (void *)rb_function_lookup_handler;
384
+ xmlXPathRegisterFuncLookup(
385
+ c_context,
386
+ _noko_xml_xpath_context_handler_lookup,
387
+ (void *)rb_function_lookup_handler
388
+ );
209
389
  }
210
390
 
211
- xmlResetLastError();
212
- xmlSetStructuredErrorFunc(NULL, Nokogiri_error_raise);
391
+ /* TODO: use xmlXPathSetErrorHandler (as of 2.13.0) */
392
+ xmlSetStructuredErrorFunc((void *)rb_errors, noko__error_array_pusher);
393
+ xmlSetGenericErrorFunc((void *)rb_errors, _noko_xml_xpath_context__generic_exception_pusher);
213
394
 
214
- /* For some reason, xmlXPathEvalExpression will blow up with a generic error */
215
- /* when there is a non existent function. */
216
- xmlSetGenericErrorFunc(NULL, xpath_generic_exception_handler);
395
+ c_xpath_object = xmlXPathEvalExpression(c_expression_str, c_context);
217
396
 
218
- xpath = xmlXPathEvalExpression(query, ctx);
219
397
  xmlSetStructuredErrorFunc(NULL, NULL);
220
398
  xmlSetGenericErrorFunc(NULL, NULL);
221
399
 
222
- if(xpath == NULL) {
223
- xmlErrorPtr error = xmlGetLastError();
224
- rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
225
- }
400
+ xmlXPathRegisterFuncLookup(c_context, NULL, NULL);
226
401
 
227
- assert(ctx->doc);
228
- assert(DOC_RUBY_OBJECT_TEST(ctx->doc));
402
+ if (c_xpath_object == NULL) {
403
+ rb_exc_raise(rb_ary_entry(rb_errors, 0));
404
+ }
229
405
 
230
- switch(xpath->type) {
231
- case XPATH_STRING:
232
- thing = NOKOGIRI_STR_NEW2(xpath->stringval);
233
- xmlFree(xpath->stringval);
234
- break;
235
- case XPATH_NODESET:
236
- thing = Nokogiri_wrap_xml_node_set(xpath->nodesetval,
237
- DOC_RUBY_OBJECT(ctx->doc));
238
- break;
239
- case XPATH_NUMBER:
240
- thing = rb_float_new(xpath->floatval);
241
- break;
242
- case XPATH_BOOLEAN:
243
- thing = xpath->boolval == 1 ? Qtrue : Qfalse;
244
- break;
245
- default:
246
- thing = Nokogiri_wrap_xml_node_set(NULL, DOC_RUBY_OBJECT(ctx->doc));
406
+ rb_xpath_object = _noko_xml_xpath_context__xpath2ruby(c_xpath_object, c_context);
407
+ if (rb_xpath_object == Qundef) {
408
+ rb_xpath_object = noko_xml_node_set_wrap(NULL, DOC_RUBY_OBJECT(c_context->doc));
247
409
  }
248
410
 
249
- xmlXPathFreeNodeSetList(xpath);
411
+ xmlXPathFreeNodeSetList(c_xpath_object);
250
412
 
251
- return thing;
413
+ return rb_xpath_object;
252
414
  }
253
415
 
254
416
  /*
255
417
  * call-seq:
256
- * new(node)
418
+ * new(node)
257
419
  *
258
- * Create a new XPathContext with +node+ as the reference point.
420
+ * Create a new XPathContext with +node+ as the context node.
259
421
  */
260
- static VALUE new(VALUE klass, VALUE nodeobj)
422
+ static VALUE
423
+ noko_xml_xpath_context_new(VALUE klass, VALUE rb_node)
261
424
  {
262
- xmlNodePtr node;
263
- xmlXPathContextPtr ctx;
264
- VALUE self;
425
+ xmlNodePtr c_node;
426
+ xmlXPathContextPtr c_context;
427
+ VALUE rb_context;
265
428
 
266
- xmlXPathInit();
429
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
267
430
 
268
- Data_Get_Struct(nodeobj, xmlNode, node);
431
+ #if LIBXML_VERSION < 21000
432
+ xmlXPathInit(); /* deprecated in 40483d0 */
433
+ #endif
269
434
 
270
- ctx = xmlXPathNewContext(node->doc);
271
- ctx->node = node;
272
- self = Data_Wrap_Struct(klass, 0, deallocate, ctx);
273
- /*rb_iv_set(self, "@xpath_handler", Qnil); */
274
- return self;
435
+ c_context = xmlXPathNewContext(c_node->doc);
436
+ c_context->node = c_node;
437
+
438
+ xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI);
439
+ xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI);
440
+
441
+ xmlXPathRegisterFuncNS(c_context,
442
+ (const xmlChar *)"css-class", NOKOGIRI_BUILTIN_URI,
443
+ noko_xml_xpath_context_xpath_func_css_class);
444
+ xmlXPathRegisterFuncNS(c_context,
445
+ (const xmlChar *)"local-name-is", NOKOGIRI_BUILTIN_URI,
446
+ noko_xml_xpath_context_xpath_func_local_name_is);
447
+
448
+ rb_context = TypedData_Wrap_Struct(klass, &_noko_xml_xpath_context_type, c_context);
449
+
450
+ return rb_context;
275
451
  }
276
452
 
277
- VALUE cNokogiriXmlXpathContext;
278
- void init_xml_xpath_context(void)
453
+
454
+ /* :nodoc: */
455
+ static VALUE
456
+ noko_xml_xpath_context_set_node(VALUE rb_context, VALUE rb_node)
279
457
  {
280
- VALUE module = rb_define_module("Nokogiri");
458
+ xmlNodePtr c_node;
459
+ xmlXPathContextPtr c_context;
281
460
 
282
- /*
283
- * Nokogiri::XML
284
- */
285
- VALUE xml = rb_define_module_under(module, "XML");
461
+ TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context);
462
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
463
+
464
+ c_context->doc = c_node->doc;
465
+ c_context->node = c_node;
466
+
467
+ return rb_node;
468
+ }
286
469
 
470
+ void
471
+ noko_init_xml_xpath_context(void)
472
+ {
287
473
  /*
288
- * XPathContext is the entry point for searching a Document by using XPath.
474
+ * XPathContext is the entry point for searching a +Document+ by using XPath.
289
475
  */
290
- VALUE klass = rb_define_class_under(xml, "XPathContext", rb_cObject);
476
+ cNokogiriXmlXpathContext = rb_define_class_under(mNokogiriXml, "XPathContext", rb_cObject);
477
+
478
+ rb_undef_alloc_func(cNokogiriXmlXpathContext);
291
479
 
292
- cNokogiriXmlXpathContext = klass;
480
+ rb_define_singleton_method(cNokogiriXmlXpathContext, "new", noko_xml_xpath_context_new, 1);
293
481
 
294
- rb_define_singleton_method(klass, "new", new, 1);
295
- rb_define_method(klass, "evaluate", evaluate, -1);
296
- rb_define_method(klass, "register_variable", register_variable, 2);
297
- rb_define_method(klass, "register_ns", register_ns, 2);
482
+ rb_define_method(cNokogiriXmlXpathContext, "evaluate", noko_xml_xpath_context_evaluate, -1);
483
+ rb_define_method(cNokogiriXmlXpathContext, "register_variable", noko_xml_xpath_context_register_variable, 2);
484
+ rb_define_method(cNokogiriXmlXpathContext, "register_ns", noko_xml_xpath_context_register_ns, 2);
485
+ rb_define_method(cNokogiriXmlXpathContext, "node=", noko_xml_xpath_context_set_node, 1);
298
486
  }