nokolexbor 0.2.2 → 0.2.4

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.
@@ -43,7 +43,7 @@ nl_rb_node_unwrap(VALUE rb_node)
43
43
  lxb_dom_node_t *node;
44
44
  if (rb_obj_class(rb_node) == cNokolexborDocument)
45
45
  {
46
- TypedData_Get_Struct(rb_node, lxb_dom_document_t, &nl_document_type, node);
46
+ TypedData_Get_Struct(rb_node, lxb_dom_node_t, &nl_document_type, node);
47
47
  }
48
48
  else
49
49
  {
@@ -56,7 +56,6 @@ static VALUE
56
56
  nl_node_new(int argc, VALUE *argv, VALUE klass)
57
57
  {
58
58
  lxb_dom_document_t *document;
59
- lxb_dom_node_t *node;
60
59
  VALUE rb_name;
61
60
  VALUE rb_document;
62
61
  VALUE rest;
@@ -68,9 +67,9 @@ nl_node_new(int argc, VALUE *argv, VALUE klass)
68
67
  rb_raise(rb_eArgError, "Document must be a Nokolexbor::Document");
69
68
  }
70
69
 
71
- TypedData_Get_Struct(rb_document, lxb_dom_document_t, &nl_document_type, document);
70
+ document = nl_rb_document_unwrap(rb_document);
72
71
 
73
- lxb_dom_element_t *element = lxb_dom_document_create_element(document, StringValueCStr(rb_name), RSTRING_LEN(rb_name), NULL);
72
+ lxb_dom_element_t *element = lxb_dom_document_create_element(document, (const lxb_char_t *)StringValueCStr(rb_name), RSTRING_LEN(rb_name), NULL);
74
73
  if (element == NULL)
75
74
  {
76
75
  rb_raise(rb_eRuntimeError, "Error creating element");
@@ -97,7 +96,7 @@ nl_node_content(VALUE self)
97
96
  {
98
97
  return rb_str_new("", 0);
99
98
  }
100
- VALUE rb_str = rb_utf8_str_new(text, str_len);
99
+ VALUE rb_str = rb_utf8_str_new((char *)text, str_len);
101
100
  lxb_dom_document_destroy_text(node->owner_document, text);
102
101
 
103
102
  return rb_str;
@@ -115,19 +114,19 @@ nl_node_get_attr(VALUE self, VALUE rb_attr)
115
114
 
116
115
  VALUE rb_attr_s = rb_String(rb_attr);
117
116
  const char *attr_c = RSTRING_PTR(rb_attr_s);
118
- int attr_len = RSTRING_LEN(rb_attr_s);
117
+ size_t attr_len = RSTRING_LEN(rb_attr_s);
119
118
 
120
- lxb_dom_element_t *element = lxb_html_interface_element(node);
119
+ lxb_dom_element_t *element = lxb_dom_interface_element(node);
121
120
 
122
- if (!lxb_dom_element_has_attribute(element, attr_c, attr_len))
121
+ if (!lxb_dom_element_has_attribute(element, (const lxb_char_t *)attr_c, attr_len))
123
122
  {
124
123
  return Qnil;
125
124
  }
126
125
 
127
126
  size_t attr_value_len;
128
- char *attr_value = lxb_dom_element_get_attribute(element, attr_c, attr_len, &attr_value_len);
127
+ const lxb_char_t *attr_value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)attr_c, attr_len, &attr_value_len);
129
128
 
130
- return rb_utf8_str_new(attr_value, attr_value_len);
129
+ return rb_utf8_str_new((const char *)attr_value, attr_value_len);
131
130
  }
132
131
 
133
132
  static VALUE
@@ -144,13 +143,13 @@ nl_node_set_attr(VALUE self, VALUE rb_attr, VALUE rb_value)
144
143
  VALUE rb_value_s = rb_String(rb_value);
145
144
 
146
145
  const char *attr_c = RSTRING_PTR(rb_attr_s);
147
- int attr_len = RSTRING_LEN(rb_attr_s);
146
+ size_t attr_len = RSTRING_LEN(rb_attr_s);
148
147
  const char *value_c = RSTRING_PTR(rb_value_s);
149
- int value_len = RSTRING_LEN(rb_value_s);
148
+ size_t value_len = RSTRING_LEN(rb_value_s);
150
149
 
151
- lxb_dom_element_t *element = lxb_html_interface_element(node);
150
+ lxb_dom_element_t *element = lxb_dom_interface_element(node);
152
151
 
153
- lxb_dom_element_set_attribute(element, attr_c, attr_len, value_c, value_len);
152
+ lxb_dom_element_set_attribute(element, (const lxb_char_t *)attr_c, attr_len, (const lxb_char_t *)value_c, value_len);
154
153
 
155
154
  return rb_value;
156
155
  }
@@ -168,14 +167,14 @@ nl_node_remove_attr(VALUE self, VALUE rb_attr)
168
167
  VALUE rb_attr_s = rb_String(rb_attr);
169
168
 
170
169
  const char *attr_c = RSTRING_PTR(rb_attr_s);
171
- int attr_len = RSTRING_LEN(rb_attr_s);
170
+ size_t attr_len = RSTRING_LEN(rb_attr_s);
172
171
 
173
- lxb_dom_element_t *element = lxb_html_interface_element(node);
172
+ lxb_dom_element_t *element = lxb_dom_interface_element(node);
174
173
 
175
- return lxb_dom_element_remove_attribute(element, attr_c, attr_len) == LXB_STATUS_OK ? Qtrue : Qfalse;
174
+ return lxb_dom_element_remove_attribute(element, (const lxb_char_t *)attr_c, attr_len) == LXB_STATUS_OK ? Qtrue : Qfalse;
176
175
  }
177
176
 
178
- static lxb_status_t
177
+ lxb_status_t
179
178
  nl_node_at_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *spec, void *ctx)
180
179
  {
181
180
  lexbor_array_t *array = (lexbor_array_t *)ctx;
@@ -188,7 +187,7 @@ nl_node_at_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *sp
188
187
  return LXB_STATUS_STOP;
189
188
  }
190
189
 
191
- static lxb_status_t
190
+ lxb_status_t
192
191
  nl_node_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *spec, void *ctx)
193
192
  {
194
193
  lexbor_array_t *array = (lexbor_array_t *)ctx;
@@ -200,11 +199,11 @@ nl_node_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *spec,
200
199
  return LXB_STATUS_OK;
201
200
  }
202
201
 
203
- static void
202
+ void
204
203
  nl_node_find(VALUE self, VALUE selector, lxb_selectors_cb_f cb, void *ctx)
205
204
  {
206
205
  const char *selector_c = StringValuePtr(selector);
207
- int selector_len = RSTRING_LEN(selector);
206
+ size_t selector_len = RSTRING_LEN(selector);
208
207
 
209
208
  lxb_dom_node_t *node = nl_rb_node_unwrap(self);
210
209
 
@@ -226,7 +225,7 @@ nl_node_find(VALUE self, VALUE selector, lxb_selectors_cb_f cb, void *ctx)
226
225
 
227
226
  /* Parse and get the log. */
228
227
  // TODO: Cache the list for reuse, improves performance
229
- lxb_css_selector_list_t *list = lxb_css_selectors_parse_relative_list(parser, selector_c, selector_len);
228
+ lxb_css_selector_list_t *list = lxb_css_selectors_parse_relative_list(parser, (const lxb_char_t *)selector_c, selector_len);
230
229
  if (parser->status != LXB_STATUS_OK)
231
230
  {
232
231
  nl_raise_lexbor_error(parser->status);
@@ -252,15 +251,15 @@ nl_node_find(VALUE self, VALUE selector, lxb_selectors_cb_f cb, void *ctx)
252
251
  static void
253
252
  mark_node_orders(lxb_dom_node_t *root)
254
253
  {
255
- int count = 1;
256
- root->user = count;
254
+ size_t count = 1;
255
+ root->user = (void *)count;
257
256
  lxb_dom_node_t *node = root;
258
257
  do
259
258
  {
260
259
  if (node->first_child != NULL)
261
260
  {
262
261
  node = node->first_child;
263
- node->user = ++count;
262
+ node->user = (void *)++count;
264
263
  }
265
264
  else
266
265
  {
@@ -275,7 +274,7 @@ mark_node_orders(lxb_dom_node_t *root)
275
274
  }
276
275
 
277
276
  node = node->next;
278
- node->user = ++count;
277
+ node->user = (void *)++count;
279
278
  }
280
279
 
281
280
  } while (true);
@@ -285,12 +284,12 @@ mark_node_orders(lxb_dom_node_t *root)
285
284
  void sort_nodes_if_necessary(VALUE selector, lxb_dom_document_t *doc, lexbor_array_t *array)
286
285
  {
287
286
  // No need to sort if there's only one selector, the results are natually in document traversal order
288
- if (strstr(RSTRING_PTR(selector), ",") != NULL)
287
+ if (strchr(RSTRING_PTR(selector), ',') != NULL)
289
288
  {
290
289
  int need_order = 0;
291
290
  // Check if we have already markded orders, note that
292
291
  // we need to order again if new nodes are added to the document
293
- for (int i = 0; i < array->length; i++)
292
+ for (size_t i = 0; i < array->length; i++)
294
293
  {
295
294
  if (((lxb_dom_node_t *)array->list[i])->user == 0)
296
295
  {
@@ -300,13 +299,13 @@ void sort_nodes_if_necessary(VALUE selector, lxb_dom_document_t *doc, lexbor_arr
300
299
  }
301
300
  if (need_order)
302
301
  {
303
- mark_node_orders(doc);
302
+ mark_node_orders(&doc->node);
304
303
  }
305
- css_result_tim_sort(&array->list[0], array->length);
304
+ css_result_tim_sort((lxb_dom_node_t **)&array->list[0], array->length);
306
305
  }
307
306
  }
308
307
 
309
- VALUE
308
+ static VALUE
310
309
  nl_node_at_css(VALUE self, VALUE selector)
311
310
  {
312
311
  lxb_dom_node_t *node = nl_rb_node_unwrap(self);
@@ -321,10 +320,14 @@ nl_node_at_css(VALUE self, VALUE selector)
321
320
 
322
321
  sort_nodes_if_necessary(selector, node->owner_document, array);
323
322
 
324
- return nl_rb_node_create(array->list[0], nl_rb_document_get(self));
323
+ VALUE ret = nl_rb_node_create(array->list[0], nl_rb_document_get(self));
324
+
325
+ lexbor_array_destroy(array, true);
326
+
327
+ return ret;
325
328
  }
326
329
 
327
- VALUE
330
+ static VALUE
328
331
  nl_node_css(VALUE self, VALUE selector)
329
332
  {
330
333
  lxb_dom_node_t *node = nl_rb_node_unwrap(self);
@@ -354,7 +357,7 @@ nl_node_inner_html(VALUE self)
354
357
 
355
358
  if (str.data != NULL)
356
359
  {
357
- VALUE ret = rb_utf8_str_new(str.data, str.length);
360
+ VALUE ret = rb_utf8_str_new((const char *)str.data, str.length);
358
361
  lexbor_str_destroy(&str, node->owner_document->text, false);
359
362
  return ret;
360
363
  }
@@ -379,7 +382,7 @@ nl_node_outer_html(VALUE self)
379
382
 
380
383
  if (str.data != NULL)
381
384
  {
382
- VALUE ret = rb_utf8_str_new(str.data, str.length);
385
+ VALUE ret = rb_utf8_str_new((const char *)str.data, str.length);
383
386
  lexbor_str_destroy(&str, node->owner_document->text, false);
384
387
  return ret;
385
388
  }
@@ -399,11 +402,11 @@ nl_node_has_key(VALUE self, VALUE rb_attr)
399
402
 
400
403
  VALUE rb_attr_s = rb_String(rb_attr);
401
404
  const char *attr_c = RSTRING_PTR(rb_attr_s);
402
- int attr_len = RSTRING_LEN(rb_attr_s);
405
+ size_t attr_len = RSTRING_LEN(rb_attr_s);
403
406
 
404
- lxb_dom_element_t *element = lxb_html_interface_element(node);
407
+ lxb_dom_element_t *element = lxb_dom_interface_element(node);
405
408
 
406
- return lxb_dom_element_has_attribute(element, attr_c, attr_len) ? Qtrue : Qfalse;
409
+ return lxb_dom_element_has_attribute(element, (const lxb_char_t *)attr_c, attr_len) ? Qtrue : Qfalse;
407
410
  }
408
411
 
409
412
  static VALUE
@@ -417,13 +420,13 @@ nl_node_keys(VALUE self)
417
420
  return ary_keys;
418
421
  }
419
422
 
420
- lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_html_interface_element(node));
423
+ lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node));
421
424
 
422
425
  while (attr != NULL)
423
426
  {
424
427
  size_t tmp_len;
425
- lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len);
426
- rb_ary_push(ary_keys, rb_utf8_str_new(tmp, tmp_len));
428
+ const lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len);
429
+ rb_ary_push(ary_keys, rb_utf8_str_new((const char *)tmp, tmp_len));
427
430
 
428
431
  attr = lxb_dom_element_next_attribute(attr);
429
432
  }
@@ -442,15 +445,19 @@ nl_node_values(VALUE self)
442
445
  return ary_values;
443
446
  }
444
447
 
445
- lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_html_interface_element(node));
448
+ lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node));
446
449
 
447
450
  while (attr != NULL)
448
451
  {
449
452
  size_t tmp_len;
450
- lxb_char_t *tmp = lxb_dom_attr_value(attr, &tmp_len);
453
+ const lxb_char_t *tmp = lxb_dom_attr_value(attr, &tmp_len);
451
454
  if (tmp != NULL)
452
455
  {
453
- rb_ary_push(ary_values, rb_utf8_str_new(tmp, tmp_len));
456
+ rb_ary_push(ary_values, rb_utf8_str_new((const char *)tmp, tmp_len));
457
+ }
458
+ else
459
+ {
460
+ rb_ary_push(ary_values, rb_str_new("", 0));
454
461
  }
455
462
 
456
463
  attr = lxb_dom_element_next_attribute(attr);
@@ -470,16 +477,16 @@ nl_node_attrs(VALUE self)
470
477
  return rb_hash;
471
478
  }
472
479
 
473
- lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_html_interface_element(node));
480
+ lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node));
474
481
 
475
482
  while (attr != NULL)
476
483
  {
477
484
  size_t tmp_len;
478
- lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len);
479
- VALUE rb_key = rb_utf8_str_new(tmp, tmp_len);
485
+ const lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len);
486
+ VALUE rb_key = rb_utf8_str_new((const char *)tmp, tmp_len);
480
487
 
481
488
  tmp = lxb_dom_attr_value(attr, &tmp_len);
482
- VALUE rb_value = tmp != NULL ? rb_utf8_str_new(tmp, tmp_len) : Qnil;
489
+ VALUE rb_value = tmp != NULL ? rb_utf8_str_new((const char *)tmp, tmp_len) : rb_str_new("", 0);
483
490
 
484
491
  rb_hash_aset(rb_hash, rb_key, rb_value);
485
492
 
@@ -604,15 +611,16 @@ nl_node_name(VALUE self)
604
611
  {
605
612
  lxb_dom_node_t *node = nl_rb_node_unwrap(self);
606
613
  size_t len;
607
- lxb_char_t *name = lxb_dom_node_name_qualified(node, &len);
608
- return rb_utf8_str_new(name, len);
614
+ const lxb_char_t *name = lxb_dom_node_name_qualified(node, &len);
615
+ return rb_utf8_str_new((const char *)name, len);
609
616
  }
610
617
 
611
618
  static lxb_dom_node_t *
612
- nl_node_parse_fragment(lxb_html_document_t *doc, lxb_char_t *html, size_t size)
619
+ nl_node_parse_fragment(lxb_dom_document_t *doc, lxb_char_t *html, size_t size)
613
620
  {
614
621
  size_t tag_name_len;
615
- lxb_char_t *tag_name = lxb_tag_name_by_id(lxb_html_document_tags(doc), LXB_TAG__UNDEF, &tag_name_len);
622
+ lxb_html_document_t *html_doc = lxb_html_interface_document(doc);
623
+ const lxb_char_t *tag_name = lxb_tag_name_by_id(lxb_html_document_tags(html_doc), LXB_TAG__UNDEF, &tag_name_len);
616
624
  if (tag_name == NULL)
617
625
  {
618
626
  rb_raise(rb_eRuntimeError, "Error getting tag name");
@@ -622,7 +630,7 @@ nl_node_parse_fragment(lxb_html_document_t *doc, lxb_char_t *html, size_t size)
622
630
  {
623
631
  rb_raise(rb_eRuntimeError, "Error creating element");
624
632
  }
625
- lxb_dom_node_t *frag_root = lxb_html_document_parse_fragment(doc, element, html, size);
633
+ lxb_dom_node_t *frag_root = lxb_html_document_parse_fragment(html_doc, element, html, size);
626
634
  if (frag_root == NULL)
627
635
  {
628
636
  rb_raise(rb_eArgError, "Error parsing HTML");
@@ -637,7 +645,7 @@ nl_node_fragment(VALUE self, VALUE html)
637
645
  lxb_dom_node_t *node = nl_rb_node_unwrap(self);
638
646
  lxb_dom_document_t *doc = node->owner_document;
639
647
 
640
- lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, RSTRING_PTR(html), RSTRING_LEN(html));
648
+ lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, (lxb_char_t *)RSTRING_PTR(html), RSTRING_LEN(html));
641
649
  return nl_rb_node_create(frag_root, nl_rb_document_get(self));
642
650
  }
643
651
 
@@ -663,7 +671,7 @@ nl_node_add_sibling(VALUE self, VALUE next_or_previous, VALUE new)
663
671
 
664
672
  if (TYPE(new) == T_STRING)
665
673
  {
666
- lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, RSTRING_PTR(new), RSTRING_LEN(new));
674
+ lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, (lxb_char_t *)RSTRING_PTR(new), RSTRING_LEN(new));
667
675
 
668
676
  while (frag_root->first_child != NULL)
669
677
  {
@@ -694,7 +702,7 @@ nl_node_add_child(VALUE self, VALUE new)
694
702
 
695
703
  if (TYPE(new) == T_STRING)
696
704
  {
697
- lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, RSTRING_PTR(new), RSTRING_LEN(new));
705
+ lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, (lxb_char_t *)RSTRING_PTR(new), RSTRING_LEN(new));
698
706
 
699
707
  while (frag_root->first_child != NULL)
700
708
  {
@@ -832,11 +840,13 @@ void Init_nl_node(void)
832
840
 
833
841
  rb_define_alias(cNokolexborNode, "attr", "[]");
834
842
  rb_define_alias(cNokolexborNode, "set_attr", "[]=");
843
+ rb_define_alias(cNokolexborNode, "delete", "remove_attr");
835
844
  rb_define_alias(cNokolexborNode, "text", "content");
836
845
  rb_define_alias(cNokolexborNode, "inner_text", "content");
837
846
  rb_define_alias(cNokolexborNode, "to_str", "content");
838
847
  rb_define_alias(cNokolexborNode, "to_html", "outer_html");
839
848
  rb_define_alias(cNokolexborNode, "to_s", "outer_html");
849
+ rb_define_alias(cNokolexborNode, "unlink", "remove");
840
850
  rb_define_alias(cNokolexborNode, "type", "node_type");
841
851
  rb_define_alias(cNokolexborNode, "dup", "clone");
842
852
  }
@@ -5,15 +5,15 @@ extern VALUE cNokolexborNode;
5
5
  VALUE cNokolexborNodeSet;
6
6
  extern rb_data_type_t nl_document_type;
7
7
 
8
- VALUE nl_node_at_css(VALUE self, VALUE selector);
9
- VALUE nl_node_css(VALUE self, VALUE selector);
10
-
11
- typedef VALUE (*nl_node_find_f)(VALUE self, VALUE selector);
8
+ void nl_node_find(VALUE self, VALUE selector, lxb_selectors_cb_f cb, void *ctx);
9
+ void sort_nodes_if_necessary(VALUE selector, lxb_dom_document_t *doc, lexbor_array_t *array);
10
+ lxb_status_t nl_node_at_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *spec, void *ctx);
11
+ lxb_status_t nl_node_css_callback(lxb_dom_node_t *node, lxb_css_selector_specificity_t *spec, void *ctx);
12
12
 
13
13
  lxb_status_t
14
14
  lexbor_array_push_unique(lexbor_array_t *array, void *value)
15
15
  {
16
- for (int i = 0; i < array->length; i++)
16
+ for (size_t i = 0; i < array->length; i++)
17
17
  if (array->list[i] == value)
18
18
  return LXB_STATUS_STOPPED;
19
19
 
@@ -91,7 +91,7 @@ nl_node_set_delete(VALUE self, VALUE rb_node)
91
91
  lexbor_array_t *array = nl_rb_node_set_unwrap(self);
92
92
  lxb_dom_node_t *node = nl_rb_node_unwrap(rb_node);
93
93
 
94
- int i;
94
+ size_t i;
95
95
  for (i = 0; i < array->length; i++)
96
96
  if (array->list[i] == node)
97
97
  {
@@ -113,7 +113,7 @@ nl_node_set_is_include(VALUE self, VALUE rb_node)
113
113
  lexbor_array_t *array = nl_rb_node_set_unwrap(self);
114
114
  lxb_dom_node_t *node = nl_rb_node_unwrap(rb_node);
115
115
 
116
- for (int i = 0; i < array->length; i++)
116
+ for (size_t i = 0; i < array->length; i++)
117
117
  if (array->list[i] == node)
118
118
  {
119
119
  return Qtrue;
@@ -169,7 +169,7 @@ nl_node_set_subseq(VALUE self, long beg, long len)
169
169
  }
170
170
  }
171
171
 
172
- for (int j = beg; j < beg + len; ++j)
172
+ for (long j = beg; j < beg + len; ++j)
173
173
  {
174
174
  lxb_status_t status = lexbor_array_push(new_array, old_array->list[j]);
175
175
  if (status != LXB_STATUS_OK)
@@ -177,7 +177,7 @@ nl_node_set_subseq(VALUE self, long beg, long len)
177
177
  nl_raise_lexbor_error(status);
178
178
  }
179
179
  }
180
- return TypedData_Wrap_Struct(cNokolexborNodeSet, &nl_node_set_type, new_array);
180
+ return nl_rb_node_set_create_with_data(new_array, nl_rb_document_get(self));
181
181
  }
182
182
 
183
183
  static VALUE
@@ -231,7 +231,7 @@ nl_node_set_to_array(VALUE self)
231
231
 
232
232
  VALUE list = rb_ary_new2(array->length);
233
233
  VALUE doc = nl_rb_document_get(self);
234
- for (int i = 0; i < array->length; i++)
234
+ for (size_t i = 0; i < array->length; i++)
235
235
  {
236
236
  lxb_dom_node_t *node = (lxb_dom_node_t *)array->list[i];
237
237
  VALUE rb_node = nl_rb_node_create(node, doc);
@@ -267,7 +267,7 @@ nl_node_set_union(VALUE self, VALUE other)
267
267
  memcpy(new_array->list, self_array->list, sizeof(lxb_dom_node_t *) * self_array->length);
268
268
  new_array->length = self_array->length;
269
269
 
270
- for (int i = 0; i < other_array->length; i++)
270
+ for (size_t i = 0; i < other_array->length; i++)
271
271
  {
272
272
  lexbor_array_push_unique(new_array, other_array->list[i]);
273
273
  }
@@ -275,16 +275,15 @@ nl_node_set_union(VALUE self, VALUE other)
275
275
  return nl_rb_node_set_create_with_data(new_array, nl_rb_document_get(self));
276
276
  }
277
277
 
278
- static VALUE
279
- nl_node_set_find(VALUE self, VALUE selector, nl_node_find_f finder)
278
+ static void
279
+ nl_node_set_find(VALUE self, VALUE selector, lxb_selectors_cb_f cb, void* ctx)
280
280
  {
281
- VALUE rb_doc = nl_rb_document_get(self);
282
- lxb_dom_document_t *doc;
283
- TypedData_Get_Struct(rb_doc, lxb_dom_document_t, &nl_document_type, doc);
281
+ lxb_dom_document_t *doc = nl_rb_document_unwrap(nl_rb_document_get(self));
284
282
  if (doc == NULL)
285
283
  {
286
284
  rb_raise(rb_eRuntimeError, "Error getting document");
287
285
  }
286
+ // Wrap direct children with a temporary fragment so that they can be searched
288
287
  lxb_dom_document_fragment_t *frag = lxb_dom_document_fragment_interface_create(doc);
289
288
  if (frag == NULL)
290
289
  {
@@ -302,7 +301,7 @@ nl_node_set_find(VALUE self, VALUE selector, nl_node_find_f finder)
302
301
  }
303
302
  }
304
303
  // Backup original node data and re-group them into a fragment
305
- for (int i = 0; i < array->length; i++)
304
+ for (size_t i = 0; i < array->length; i++)
306
305
  {
307
306
  lxb_dom_node_t *node = (lxb_dom_node_t *)array->list[i];
308
307
  lxb_dom_node_t *backup_node = malloc(sizeof(lxb_dom_node_t));
@@ -320,29 +319,51 @@ nl_node_set_find(VALUE self, VALUE selector, nl_node_find_f finder)
320
319
  }
321
320
  VALUE rb_frag = nl_rb_node_create(&frag->node, nl_rb_document_get(self));
322
321
 
323
- VALUE ret = finder(rb_frag, selector);
322
+ nl_node_find(rb_frag, selector, cb, ctx);
324
323
 
325
324
  lxb_dom_document_fragment_interface_destroy(frag);
326
325
  // Restore original node data
327
- for (int i = 0; i < array->length; i++)
326
+ for (size_t i = 0; i < array->length; i++)
328
327
  {
329
328
  memcpy(array->list[i], backup_array->list[i], sizeof(lxb_dom_node_t));
330
329
  free(backup_array->list[i]);
331
330
  }
332
331
  lexbor_array_destroy(backup_array, true);
333
- return ret;
334
332
  }
335
333
 
336
334
  static VALUE
337
335
  nl_node_set_at_css(VALUE self, VALUE selector)
338
336
  {
339
- return nl_node_set_find(self, selector, nl_node_at_css);
337
+ lexbor_array_t *array = lexbor_array_create();
338
+ lxb_dom_document_t *doc = nl_rb_document_unwrap(nl_rb_document_get(self));
339
+
340
+ nl_node_set_find(self, selector, nl_node_at_css_callback, array);
341
+
342
+ if (array->length == 0)
343
+ {
344
+ return Qnil;
345
+ }
346
+
347
+ sort_nodes_if_necessary(selector, doc, array);
348
+
349
+ VALUE ret = nl_rb_node_create(array->list[0], nl_rb_document_get(self));
350
+
351
+ lexbor_array_destroy(array, true);
352
+
353
+ return ret;
340
354
  }
341
355
 
342
356
  static VALUE
343
357
  nl_node_set_css(VALUE self, VALUE selector)
344
358
  {
345
- return nl_node_set_find(self, selector, nl_node_css);
359
+ lexbor_array_t *array = lexbor_array_create();
360
+ lxb_dom_document_t *doc = nl_rb_document_unwrap(nl_rb_document_get(self));
361
+
362
+ nl_node_set_find(self, selector, nl_node_css_callback, array);
363
+
364
+ sort_nodes_if_necessary(selector, doc, array);
365
+
366
+ return nl_rb_node_set_create_with_data(array, nl_rb_document_get(self));
346
367
  }
347
368
 
348
369
  void Init_nl_node_set(void)