nokogiri 1.12.5 → 1.13.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.

Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +9 -7
  4. data/bin/nokogiri +63 -50
  5. data/dependencies.yml +5 -6
  6. data/ext/nokogiri/extconf.rb +47 -35
  7. data/ext/nokogiri/xml_document.c +35 -35
  8. data/ext/nokogiri/xml_document_fragment.c +0 -2
  9. data/ext/nokogiri/xml_dtd.c +2 -2
  10. data/ext/nokogiri/xml_encoding_handler.c +25 -11
  11. data/ext/nokogiri/xml_node.c +638 -333
  12. data/ext/nokogiri/xml_reader.c +37 -11
  13. data/ext/nokogiri/xml_xpath_context.c +72 -49
  14. data/gumbo-parser/src/parser.c +0 -11
  15. data/lib/nokogiri/class_resolver.rb +67 -0
  16. data/lib/nokogiri/css/node.rb +9 -8
  17. data/lib/nokogiri/css/parser.rb +11 -3
  18. data/lib/nokogiri/css/parser.y +10 -2
  19. data/lib/nokogiri/css/parser_extras.rb +20 -20
  20. data/lib/nokogiri/css/syntax_error.rb +1 -0
  21. data/lib/nokogiri/css/tokenizer.rb +2 -1
  22. data/lib/nokogiri/css/tokenizer.rex +2 -1
  23. data/lib/nokogiri/css/xpath_visitor.rb +174 -75
  24. data/lib/nokogiri/css.rb +38 -6
  25. data/lib/nokogiri/decorators/slop.rb +8 -7
  26. data/lib/nokogiri/extension.rb +1 -1
  27. data/lib/nokogiri/gumbo.rb +1 -0
  28. data/lib/nokogiri/html.rb +16 -10
  29. data/lib/nokogiri/html4/builder.rb +1 -0
  30. data/lib/nokogiri/html4/document.rb +84 -75
  31. data/lib/nokogiri/html4/document_fragment.rb +11 -7
  32. data/lib/nokogiri/html4/element_description.rb +1 -0
  33. data/lib/nokogiri/html4/element_description_defaults.rb +426 -520
  34. data/lib/nokogiri/html4/entity_lookup.rb +2 -1
  35. data/lib/nokogiri/html4/sax/parser.rb +2 -1
  36. data/lib/nokogiri/html4/sax/parser_context.rb +1 -0
  37. data/lib/nokogiri/html4/sax/push_parser.rb +7 -7
  38. data/lib/nokogiri/html4.rb +11 -5
  39. data/lib/nokogiri/html5/document.rb +24 -10
  40. data/lib/nokogiri/html5/document_fragment.rb +5 -2
  41. data/lib/nokogiri/html5/node.rb +6 -3
  42. data/lib/nokogiri/html5.rb +68 -64
  43. data/lib/nokogiri/jruby/dependencies.rb +10 -9
  44. data/lib/nokogiri/syntax_error.rb +1 -0
  45. data/lib/nokogiri/version/constant.rb +2 -1
  46. data/lib/nokogiri/version/info.rb +19 -13
  47. data/lib/nokogiri/version.rb +1 -0
  48. data/lib/nokogiri/xml/attr.rb +5 -3
  49. data/lib/nokogiri/xml/attribute_decl.rb +2 -1
  50. data/lib/nokogiri/xml/builder.rb +32 -32
  51. data/lib/nokogiri/xml/cdata.rb +2 -1
  52. data/lib/nokogiri/xml/character_data.rb +1 -0
  53. data/lib/nokogiri/xml/document.rb +139 -103
  54. data/lib/nokogiri/xml/document_fragment.rb +41 -38
  55. data/lib/nokogiri/xml/dtd.rb +3 -2
  56. data/lib/nokogiri/xml/element_content.rb +1 -0
  57. data/lib/nokogiri/xml/element_decl.rb +2 -1
  58. data/lib/nokogiri/xml/entity_decl.rb +3 -2
  59. data/lib/nokogiri/xml/entity_reference.rb +1 -0
  60. data/lib/nokogiri/xml/namespace.rb +2 -0
  61. data/lib/nokogiri/xml/node/save_options.rb +6 -3
  62. data/lib/nokogiri/xml/node.rb +512 -348
  63. data/lib/nokogiri/xml/node_set.rb +46 -54
  64. data/lib/nokogiri/xml/notation.rb +12 -0
  65. data/lib/nokogiri/xml/parse_options.rb +11 -7
  66. data/lib/nokogiri/xml/pp/character_data.rb +8 -6
  67. data/lib/nokogiri/xml/pp/node.rb +24 -26
  68. data/lib/nokogiri/xml/pp.rb +1 -0
  69. data/lib/nokogiri/xml/processing_instruction.rb +2 -1
  70. data/lib/nokogiri/xml/reader.rb +17 -19
  71. data/lib/nokogiri/xml/relax_ng.rb +1 -0
  72. data/lib/nokogiri/xml/sax/document.rb +20 -19
  73. data/lib/nokogiri/xml/sax/parser.rb +36 -34
  74. data/lib/nokogiri/xml/sax/parser_context.rb +7 -3
  75. data/lib/nokogiri/xml/sax/push_parser.rb +5 -5
  76. data/lib/nokogiri/xml/sax.rb +1 -0
  77. data/lib/nokogiri/xml/schema.rb +7 -6
  78. data/lib/nokogiri/xml/searchable.rb +42 -22
  79. data/lib/nokogiri/xml/syntax_error.rb +4 -4
  80. data/lib/nokogiri/xml/text.rb +1 -0
  81. data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
  82. data/lib/nokogiri/xml/xpath.rb +12 -0
  83. data/lib/nokogiri/xml/xpath_context.rb +2 -3
  84. data/lib/nokogiri/xml.rb +3 -3
  85. data/lib/nokogiri/xslt/stylesheet.rb +1 -0
  86. data/lib/nokogiri/xslt.rb +3 -2
  87. data/lib/nokogiri.rb +19 -16
  88. data/lib/xsd/xmlparser/nokogiri.rb +25 -24
  89. data/patches/libxml2/0008-htmlParseComment-handle-abruptly-closed-comments.patch +61 -0
  90. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  91. metadata +101 -27
@@ -1,22 +1,27 @@
1
1
  #include <nokogiri.h>
2
2
 
3
- VALUE cNokogiriXmlNode ;
3
+ // :stopdoc:
4
4
 
5
+ VALUE cNokogiriXmlNode ;
5
6
  static ID id_decorate, id_decorate_bang;
6
7
 
8
+ typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
9
+
10
+
7
11
  #ifdef DEBUG
8
12
  static void
9
- debug_node_dealloc(xmlNodePtr x)
13
+ _xml_node_dealloc(xmlNodePtr x)
10
14
  {
11
15
  NOKOGIRI_DEBUG_START(x)
12
16
  NOKOGIRI_DEBUG_END(x)
13
17
  }
14
18
  #else
15
- # define debug_node_dealloc 0
19
+ # define _xml_node_dealloc 0
16
20
  #endif
17
21
 
22
+
18
23
  static void
19
- mark(xmlNodePtr node)
24
+ _xml_node_mark(xmlNodePtr node)
20
25
  {
21
26
  xmlDocPtr doc = node->doc;
22
27
  if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
@@ -28,10 +33,7 @@ mark(xmlNodePtr node)
28
33
  }
29
34
  }
30
35
 
31
- /* :nodoc: */
32
- typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
33
36
 
34
- /* :nodoc: */
35
37
  static void
36
38
  relink_namespace(xmlNodePtr reparented)
37
39
  {
@@ -143,7 +145,9 @@ relink_namespace(xmlNodePtr reparented)
143
145
  }
144
146
  }
145
147
 
146
- /* :nodoc: */
148
+
149
+ /* internal function meant to wrap xmlReplaceNode
150
+ and fix some issues we have with libxml2 merging nodes */
147
151
  static xmlNodePtr
148
152
  xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
149
153
  {
@@ -168,7 +172,18 @@ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
168
172
  return retval ;
169
173
  }
170
174
 
171
- /* :nodoc: */
175
+
176
+ static void
177
+ raise_if_ancestor_of_self(xmlNodePtr self)
178
+ {
179
+ for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
180
+ if (self == ancestor) {
181
+ rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
182
+ }
183
+ }
184
+ }
185
+
186
+
172
187
  static VALUE
173
188
  reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
174
189
  {
@@ -357,25 +372,397 @@ ok:
357
372
  * adjacent text nodes.
358
373
  */
359
374
  DATA_PTR(reparentee_obj) = reparented ;
360
-
361
- relink_namespace(reparented);
362
-
363
375
  reparented_obj = noko_xml_node_wrap(Qnil, reparented);
364
376
 
365
377
  rb_funcall(reparented_obj, id_decorate_bang, 0);
366
378
 
379
+ /* if we've created a cycle, raise an exception */
380
+ raise_if_ancestor_of_self(reparented);
381
+
382
+ relink_namespace(reparented);
383
+
367
384
  return reparented_obj ;
368
385
  }
369
386
 
387
+ // :startdoc:
370
388
 
371
389
  /*
372
- * call-seq:
373
- * document
390
+ * :call-seq:
391
+ * add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
392
+ * add_namespace(prefix, href) → Nokogiri::XML::Namespace
393
+ *
394
+ * :category: Manipulating Document Structure
395
+ *
396
+ * Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
397
+ * included an attribute "xmlns:prefix=href".
398
+ *
399
+ * A default namespace definition for this node can be added by passing +nil+ for +prefix+.
400
+ *
401
+ * [Parameters]
402
+ * - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
403
+ * - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
404
+ *
405
+ * [Returns] The new Nokogiri::XML::Namespace
406
+ *
407
+ * *Example:* adding a non-default namespace definition
408
+ *
409
+ * doc = Nokogiri::XML("<store><inventory></inventory></store>")
410
+ * inventory = doc.at_css("inventory")
411
+ * inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
412
+ * inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
413
+ * inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
414
+ * doc.to_xml
415
+ * # => "<?xml version=\"1.0\"?>\n" +
416
+ * # "<store>\n" +
417
+ * # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
418
+ * # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
419
+ * # " </inventory>\n" +
420
+ * # "</store>\n"
421
+ *
422
+ * *Example:* adding a default namespace definition
423
+ *
424
+ * doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
425
+ * doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
426
+ * doc.to_xml
427
+ * # => "<?xml version=\"1.0\"?>\n" +
428
+ * # "<store>\n" +
429
+ * # " <inventory>\n" +
430
+ * # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
431
+ * # " </inventory>\n" +
432
+ * # "</store>\n"
374
433
  *
375
- * Get the document for this Node
376
434
  */
377
435
  static VALUE
378
- document(VALUE self)
436
+ rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
437
+ {
438
+ xmlNodePtr c_node, element;
439
+ xmlNsPtr c_namespace;
440
+ const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
441
+
442
+ Data_Get_Struct(rb_node, xmlNode, c_node);
443
+ element = c_node ;
444
+
445
+ c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
446
+
447
+ if (!c_namespace) {
448
+ if (c_node->type != XML_ELEMENT_NODE) {
449
+ element = c_node->parent;
450
+ }
451
+ c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
452
+ }
453
+
454
+ if (!c_namespace) {
455
+ return Qnil ;
456
+ }
457
+
458
+ if (NIL_P(rb_prefix) || c_node != element) {
459
+ xmlSetNs(c_node, c_namespace);
460
+ }
461
+
462
+ return noko_xml_namespace_wrap(c_namespace, c_node->doc);
463
+ }
464
+
465
+
466
+ /*
467
+ * :call-seq: attribute(name) → Nokogiri::XML::Attr
468
+ *
469
+ * :category: Working With Node Attributes
470
+ *
471
+ * [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
472
+ *
473
+ * ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
474
+ * used to find a matching attribute. In case of a simple name collision, only one of the matching
475
+ * attributes will be returned. In this case, you will need to use #attribute_with_ns.
476
+ *
477
+ * *Example:*
478
+ *
479
+ * doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
480
+ * child = doc.at_css("child")
481
+ * child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
482
+ * child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
483
+ *
484
+ * *Example* showing that namespaced attributes will not be returned:
485
+ *
486
+ * ⚠ Note that only one of the two matching attributes is returned.
487
+ *
488
+ * doc = Nokogiri::XML(<<~EOF)
489
+ * <root xmlns:width='http://example.com/widths'
490
+ * xmlns:height='http://example.com/heights'>
491
+ * <child width:size='broad' height:size='tall'/>
492
+ * </root>
493
+ * EOF
494
+ * doc.at_css("child").attribute("size")
495
+ * # => #(Attr:0x550 {
496
+ * # name = "size",
497
+ * # namespace = #(Namespace:0x564 {
498
+ * # prefix = "width",
499
+ * # href = "http://example.com/widths"
500
+ * # }),
501
+ * # value = "broad"
502
+ * # })
503
+ */
504
+ static VALUE
505
+ rb_xml_node_attribute(VALUE self, VALUE name)
506
+ {
507
+ xmlNodePtr node;
508
+ xmlAttrPtr prop;
509
+ Data_Get_Struct(self, xmlNode, node);
510
+ prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
511
+
512
+ if (! prop) { return Qnil; }
513
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
514
+ }
515
+
516
+
517
+ /*
518
+ * :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
519
+ *
520
+ * :category: Working With Node Attributes
521
+ *
522
+ * [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
523
+ *
524
+ * Note that this is the preferred alternative to #attributes when the simple
525
+ * (non-namespace-prefixed) attribute names may collide.
526
+ *
527
+ * *Example:*
528
+ *
529
+ * Contrast this with the colliding-name example from #attributes.
530
+ *
531
+ * doc = Nokogiri::XML(<<~EOF)
532
+ * <root xmlns:width='http://example.com/widths'
533
+ * xmlns:height='http://example.com/heights'>
534
+ * <child width:size='broad' height:size='tall'/>
535
+ * </root>
536
+ * EOF
537
+ * doc.at_css("child").attribute_nodes
538
+ * # => [#(Attr:0x550 {
539
+ * # name = "size",
540
+ * # namespace = #(Namespace:0x564 {
541
+ * # prefix = "width",
542
+ * # href = "http://example.com/widths"
543
+ * # }),
544
+ * # value = "broad"
545
+ * # }),
546
+ * # #(Attr:0x578 {
547
+ * # name = "size",
548
+ * # namespace = #(Namespace:0x58c {
549
+ * # prefix = "height",
550
+ * # href = "http://example.com/heights"
551
+ * # }),
552
+ * # value = "tall"
553
+ * # })]
554
+ */
555
+ static VALUE
556
+ rb_xml_node_attribute_nodes(VALUE rb_node)
557
+ {
558
+ xmlNodePtr c_node;
559
+
560
+ Data_Get_Struct(rb_node, xmlNode, c_node);
561
+
562
+ return noko_xml_node_attrs(c_node);
563
+ }
564
+
565
+
566
+ /*
567
+ * :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
568
+ *
569
+ * :category: Working With Node Attributes
570
+ *
571
+ * [Returns]
572
+ * Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
573
+ *
574
+ * [Parameters]
575
+ * - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
576
+ * - +namespace+ (String): the URI of the attribute's namespace
577
+ *
578
+ * See related: #attribute
579
+ *
580
+ * *Example:*
581
+ *
582
+ * doc = Nokogiri::XML(<<~EOF)
583
+ * <root xmlns:width='http://example.com/widths'
584
+ * xmlns:height='http://example.com/heights'>
585
+ * <child width:size='broad' height:size='tall'/>
586
+ * </root>
587
+ * EOF
588
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
589
+ * # => #(Attr:0x550 {
590
+ * # name = "size",
591
+ * # namespace = #(Namespace:0x564 {
592
+ * # prefix = "width",
593
+ * # href = "http://example.com/widths"
594
+ * # }),
595
+ * # value = "broad"
596
+ * # })
597
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
598
+ * # => #(Attr:0x578 {
599
+ * # name = "size",
600
+ * # namespace = #(Namespace:0x58c {
601
+ * # prefix = "height",
602
+ * # href = "http://example.com/heights"
603
+ * # }),
604
+ * # value = "tall"
605
+ * # })
606
+ */
607
+ static VALUE
608
+ rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
609
+ {
610
+ xmlNodePtr node;
611
+ xmlAttrPtr prop;
612
+ Data_Get_Struct(self, xmlNode, node);
613
+ prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
614
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
615
+
616
+ if (! prop) { return Qnil; }
617
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
618
+ }
619
+
620
+
621
+
622
+ /*
623
+ * call-seq: blank? → Boolean
624
+ *
625
+ * [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
626
+ *
627
+ * *Example:*
628
+ *
629
+ * Nokogiri("<root><child/></root>").root.child.blank? # => false
630
+ * Nokogiri("<root>\t \n</root>").root.child.blank? # => true
631
+ * Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
632
+ * Nokogiri("<root>not-blank</root>").root.child
633
+ * .tap { |n| n.content = "" }.blank # => true
634
+ */
635
+ static VALUE
636
+ rb_xml_node_blank_eh(VALUE self)
637
+ {
638
+ xmlNodePtr node;
639
+ Data_Get_Struct(self, xmlNode, node);
640
+ return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
641
+ }
642
+
643
+
644
+ /*
645
+ * :call-seq: child() → Nokogiri::XML::Node
646
+ *
647
+ * :category: Traversing Document Structure
648
+ *
649
+ * [Returns] First of this node's children, or +nil+ if there are no children
650
+ *
651
+ * This is a convenience method and is equivalent to:
652
+ *
653
+ * node.children.first
654
+ *
655
+ * See related: #children
656
+ */
657
+ static VALUE
658
+ rb_xml_node_child(VALUE self)
659
+ {
660
+ xmlNodePtr node, child;
661
+ Data_Get_Struct(self, xmlNode, node);
662
+
663
+ child = node->children;
664
+ if (!child) { return Qnil; }
665
+
666
+ return noko_xml_node_wrap(Qnil, child);
667
+ }
668
+
669
+
670
+ /*
671
+ * :call-seq: children() → Nokogiri::XML::NodeSet
672
+ *
673
+ * :category: Traversing Document Structure
674
+ *
675
+ * [Returns] Nokogiri::XML::NodeSet containing this node's children.
676
+ */
677
+ static VALUE
678
+ rb_xml_node_children(VALUE self)
679
+ {
680
+ xmlNodePtr node;
681
+ xmlNodePtr child;
682
+ xmlNodeSetPtr set;
683
+ VALUE document;
684
+ VALUE node_set;
685
+
686
+ Data_Get_Struct(self, xmlNode, node);
687
+
688
+ child = node->children;
689
+ set = xmlXPathNodeSetCreate(child);
690
+
691
+ document = DOC_RUBY_OBJECT(node->doc);
692
+
693
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
694
+
695
+ child = child->next;
696
+ while (NULL != child) {
697
+ xmlXPathNodeSetAddUnique(set, child);
698
+ child = child->next;
699
+ }
700
+
701
+ node_set = noko_xml_node_set_wrap(set, document);
702
+
703
+ return node_set;
704
+ }
705
+
706
+
707
+ /*
708
+ * :call-seq:
709
+ * content() → String
710
+ * inner_text() → String
711
+ * text() → String
712
+ * to_str() → String
713
+ *
714
+ * [Returns]
715
+ * Contents of all the text nodes in this node's subtree, concatenated together into a single
716
+ * String.
717
+ *
718
+ * ⚠ Note that entities will _always_ be expanded in the returned String.
719
+ *
720
+ * See related: #inner_html
721
+ *
722
+ * *Example* of how entities are handled:
723
+ *
724
+ * Note that <tt>&lt;</tt> becomes <tt><</tt> in the returned String.
725
+ *
726
+ * doc = Nokogiri::XML.fragment("<child>a &lt; b</child>")
727
+ * doc.at_css("child").content
728
+ * # => "a < b"
729
+ *
730
+ * *Example* of how a subtree is handled:
731
+ *
732
+ * Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
733
+ * concatenated into a single string.
734
+ *
735
+ * doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
736
+ * doc.at_css("child").content
737
+ * # => "first second"
738
+ */
739
+ static VALUE
740
+ rb_xml_node_content(VALUE self)
741
+ {
742
+ xmlNodePtr node;
743
+ xmlChar *content;
744
+
745
+ Data_Get_Struct(self, xmlNode, node);
746
+
747
+ content = xmlNodeGetContent(node);
748
+ if (content) {
749
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
750
+ xmlFree(content);
751
+ return rval;
752
+ }
753
+ return Qnil;
754
+ }
755
+
756
+
757
+ /*
758
+ * :call-seq: document() → Nokogiri::XML::Document
759
+ *
760
+ * :category: Traversing Document Structure
761
+ *
762
+ * [Returns] Parent Nokogiri::XML::Document for this node
763
+ */
764
+ static VALUE
765
+ rb_xml_node_document(VALUE self)
379
766
  {
380
767
  xmlNodePtr node;
381
768
  Data_Get_Struct(self, xmlNode, node);
@@ -383,13 +770,14 @@ document(VALUE self)
383
770
  }
384
771
 
385
772
  /*
386
- * call-seq:
387
- * pointer_id
773
+ * :call-seq: pointer_id() → Integer
388
774
  *
389
- * Get the internal pointer number
775
+ * [Returns]
776
+ * A unique id for this node based on the internal memory structures. This method is used by #==
777
+ * to determine node identity.
390
778
  */
391
779
  static VALUE
392
- pointer_id(VALUE self)
780
+ rb_xml_node_pointer_id(VALUE self)
393
781
  {
394
782
  xmlNodePtr node;
395
783
  Data_Get_Struct(self, xmlNode, node);
@@ -398,8 +786,7 @@ pointer_id(VALUE self)
398
786
  }
399
787
 
400
788
  /*
401
- * call-seq:
402
- * encode_special_chars(string)
789
+ * :call-seq: encode_special_chars(string) → String
403
790
  *
404
791
  * Encode any special characters in +string+
405
792
  */
@@ -423,8 +810,8 @@ encode_special_chars(VALUE self, VALUE string)
423
810
  }
424
811
 
425
812
  /*
426
- * call-seq:
427
- * create_internal_subset(name, external_id, system_id)
813
+ * :call-seq:
814
+ * create_internal_subset(name, external_id, system_id)
428
815
  *
429
816
  * Create the internal subset of a document.
430
817
  *
@@ -462,8 +849,8 @@ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
462
849
  }
463
850
 
464
851
  /*
465
- * call-seq:
466
- * create_external_subset(name, external_id, system_id)
852
+ * :call-seq:
853
+ * create_external_subset(name, external_id, system_id)
467
854
  *
468
855
  * Create an external subset
469
856
  */
@@ -495,8 +882,8 @@ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
495
882
  }
496
883
 
497
884
  /*
498
- * call-seq:
499
- * external_subset
885
+ * :call-seq:
886
+ * external_subset()
500
887
  *
501
888
  * Get the external subset
502
889
  */
@@ -520,8 +907,8 @@ external_subset(VALUE self)
520
907
  }
521
908
 
522
909
  /*
523
- * call-seq:
524
- * internal_subset
910
+ * :call-seq:
911
+ * internal_subset()
525
912
  *
526
913
  * Get the internal subset
527
914
  */
@@ -545,16 +932,19 @@ internal_subset(VALUE self)
545
932
  }
546
933
 
547
934
  /*
548
- * call-seq:
549
- * dup
550
- * dup(depth)
551
- * dup(depth, new_parent_doc)
935
+ * :call-seq:
936
+ * dup → Nokogiri::XML::Node
937
+ * dup(depth) → Nokogiri::XML::Node
938
+ * dup(depth, new_parent_doc) → Nokogiri::XML::Node
552
939
  *
553
940
  * Copy this node.
554
- * An optional depth may be passed in. 0 is a shallow copy, 1 (the default) is a deep copy.
555
- * An optional new_parent_doc may also be passed in, which will be the new
556
- * node's parent document. Defaults to the current node's document.
557
- * current document.
941
+ *
942
+ * [Parameters]
943
+ * - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
944
+ * - +new_parent_doc+
945
+ * The new node's parent Document. Defaults to the this node's document.
946
+ *
947
+ * [Returns] The new Nokgiri::XML::Node
558
948
  */
559
949
  static VALUE
560
950
  duplicate_node(int argc, VALUE *argv, VALUE self)
@@ -589,8 +979,8 @@ duplicate_node(int argc, VALUE *argv, VALUE self)
589
979
  }
590
980
 
591
981
  /*
592
- * call-seq:
593
- * unlink
982
+ * :call-seq:
983
+ * unlink() → self
594
984
  *
595
985
  * Unlink this node from its current context.
596
986
  */
@@ -604,19 +994,6 @@ unlink_node(VALUE self)
604
994
  return self;
605
995
  }
606
996
 
607
- /*
608
- * call-seq:
609
- * blank?
610
- *
611
- * Is this node blank?
612
- */
613
- static VALUE
614
- blank_eh(VALUE self)
615
- {
616
- xmlNodePtr node;
617
- Data_Get_Struct(self, xmlNode, node);
618
- return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
619
- }
620
997
 
621
998
  /*
622
999
  * call-seq:
@@ -711,53 +1088,27 @@ replace(VALUE self, VALUE new_node)
711
1088
  }
712
1089
 
713
1090
  /*
714
- * call-seq:
715
- * children
1091
+ * :call-seq:
1092
+ * element_children() → NodeSet
1093
+ * elements() → NodeSet
716
1094
  *
717
- * Get the list of children for this node as a NodeSet
718
- */
719
- static VALUE
720
- children(VALUE self)
721
- {
722
- xmlNodePtr node;
723
- xmlNodePtr child;
724
- xmlNodeSetPtr set;
725
- VALUE document;
726
- VALUE node_set;
727
-
728
- Data_Get_Struct(self, xmlNode, node);
729
-
730
- child = node->children;
731
- set = xmlXPathNodeSetCreate(child);
732
-
733
- document = DOC_RUBY_OBJECT(node->doc);
734
-
735
- if (!child) { return noko_xml_node_set_wrap(set, document); }
736
-
737
- child = child->next;
738
- while (NULL != child) {
739
- xmlXPathNodeSetAddUnique(set, child);
740
- child = child->next;
741
- }
742
-
743
- node_set = noko_xml_node_set_wrap(set, document);
744
-
745
- return node_set;
746
- }
747
-
748
- /*
749
- * call-seq:
750
- * element_children
1095
+ * [Returns]
1096
+ * The node's child elements as a NodeSet. Only children that are elements will be returned, which
1097
+ * notably excludes Text nodes.
751
1098
  *
752
- * Get the list of children for this node as a NodeSet. All nodes will be
753
- * element nodes.
1099
+ * *Example:*
754
1100
  *
755
- * Example:
1101
+ * Note that #children returns the Text node "hello" while #element_children does not.
756
1102
  *
757
- * @doc.root.element_children.all? { |x| x.element? } # => true
1103
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1104
+ * div.element_children
1105
+ * # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
1106
+ * div.children
1107
+ * # => [#<Nokogiri::XML::Text:0x64 "hello">,
1108
+ * # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
758
1109
  */
759
1110
  static VALUE
760
- element_children(VALUE self)
1111
+ rb_xml_node_element_children(VALUE self)
761
1112
  {
762
1113
  xmlNodePtr node;
763
1114
  xmlNodePtr child;
@@ -786,35 +1137,22 @@ element_children(VALUE self)
786
1137
  }
787
1138
 
788
1139
  /*
789
- * call-seq:
790
- * child
1140
+ * :call-seq:
1141
+ * first_element_child() → Node
791
1142
  *
792
- * Returns the child node
793
- */
794
- static VALUE
795
- child(VALUE self)
796
- {
797
- xmlNodePtr node, child;
798
- Data_Get_Struct(self, xmlNode, node);
799
-
800
- child = node->children;
801
- if (!child) { return Qnil; }
802
-
803
- return noko_xml_node_wrap(Qnil, child);
804
- }
805
-
806
- /*
807
- * call-seq:
808
- * first_element_child
1143
+ * [Returns] The first child Node that is an element.
809
1144
  *
810
- * Returns the first child node of this node that is an element.
1145
+ * *Example:*
811
1146
  *
812
- * Example:
1147
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
1148
+ * returned.
813
1149
  *
814
- * @doc.root.first_element_child.element? # => true
1150
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1151
+ * div.first_element_child
1152
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
815
1153
  */
816
1154
  static VALUE
817
- first_element_child(VALUE self)
1155
+ rb_xml_node_first_element_child(VALUE self)
818
1156
  {
819
1157
  xmlNodePtr node, child;
820
1158
  Data_Get_Struct(self, xmlNode, node);
@@ -826,17 +1164,22 @@ first_element_child(VALUE self)
826
1164
  }
827
1165
 
828
1166
  /*
829
- * call-seq:
830
- * last_element_child
1167
+ * :call-seq:
1168
+ * last_element_child() → Node
831
1169
  *
832
- * Returns the last child node of this node that is an element.
1170
+ * [Returns] The last child Node that is an element.
833
1171
  *
834
- * Example:
1172
+ * *Example:*
835
1173
  *
836
- * @doc.root.last_element_child.element? # => true
1174
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
1175
+ * element is returned.
1176
+ *
1177
+ * div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
1178
+ * div.last_element_child
1179
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
837
1180
  */
838
1181
  static VALUE
839
- last_element_child(VALUE self)
1182
+ rb_xml_node_last_element_child(VALUE self)
840
1183
  {
841
1184
  xmlNodePtr node, child;
842
1185
  Data_Get_Struct(self, xmlNode, node);
@@ -992,67 +1335,29 @@ set_namespace(VALUE self, VALUE namespace)
992
1335
  }
993
1336
 
994
1337
  /*
995
- * call-seq:
996
- * attribute(name)
1338
+ * :call-seq:
1339
+ * namespace() → Namespace
997
1340
  *
998
- * Get the attribute node with +name+
999
- */
1000
- static VALUE
1001
- attr(VALUE self, VALUE name)
1002
- {
1003
- xmlNodePtr node;
1004
- xmlAttrPtr prop;
1005
- Data_Get_Struct(self, xmlNode, node);
1006
- prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
1007
-
1008
- if (! prop) { return Qnil; }
1009
- return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
1010
- }
1011
-
1012
- /*
1013
- * call-seq:
1014
- * attribute_with_ns(name, namespace)
1341
+ * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
1015
1342
  *
1016
- * Get the attribute node with +name+ and +namespace+
1017
- */
1018
- static VALUE
1019
- attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
1020
- {
1021
- xmlNodePtr node;
1022
- xmlAttrPtr prop;
1023
- Data_Get_Struct(self, xmlNode, node);
1024
- prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
1025
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
1026
-
1027
- if (! prop) { return Qnil; }
1028
- return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
1029
- }
1030
-
1031
- /*
1032
- * @overload attribute_nodes()
1033
- * Get the attributes for a Node
1034
- * @return [Array<Nokogiri::XML::Attr>] containing the Node's attributes.
1035
- */
1036
- static VALUE
1037
- attribute_nodes(VALUE rb_node)
1038
- {
1039
- xmlNodePtr c_node;
1040
-
1041
- Data_Get_Struct(rb_node, xmlNode, c_node);
1042
-
1043
- return noko_xml_node_attrs(c_node);
1044
- }
1045
-
1046
-
1047
- /*
1048
- * call-seq:
1049
- * namespace()
1343
+ * *Example:*
1050
1344
  *
1051
- * returns the namespace of the element or attribute node as a Namespace
1052
- * object, or nil if there is no namespace for the element or attribute.
1345
+ * doc = Nokogiri::XML(<<~EOF)
1346
+ * <root>
1347
+ * <first/>
1348
+ * <second xmlns="http://example.com/child"/>
1349
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1350
+ * </root>
1351
+ * EOF
1352
+ * doc.at_xpath("//first").namespace
1353
+ * # => nil
1354
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
1355
+ * # => #(Namespace:0x3c { href = "http://example.com/child" })
1356
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
1357
+ * # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
1053
1358
  */
1054
1359
  static VALUE
1055
- noko_xml_node_namespace(VALUE rb_node)
1360
+ rb_xml_node_namespace(VALUE rb_node)
1056
1361
  {
1057
1362
  xmlNodePtr c_node ;
1058
1363
  Data_Get_Struct(rb_node, xmlNode, c_node);
@@ -1065,10 +1370,32 @@ noko_xml_node_namespace(VALUE rb_node)
1065
1370
  }
1066
1371
 
1067
1372
  /*
1068
- * call-seq:
1069
- * namespace_definitions()
1373
+ * :call-seq:
1374
+ * namespace_definitions() → Array<Nokogiri::XML::Namespace>
1375
+ *
1376
+ * [Returns]
1377
+ * Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
1378
+ * will be empty if no namespaces are defined on this node.
1379
+ *
1380
+ * *Example:*
1070
1381
  *
1071
- * returns namespaces defined on self element directly, as an array of Namespace objects. Includes both a default namespace (as in"xmlns="), and prefixed namespaces (as in "xmlns:prefix=").
1382
+ * doc = Nokogiri::XML(<<~EOF)
1383
+ * <root xmlns="http://example.com/root">
1384
+ * <first/>
1385
+ * <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
1386
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1387
+ * </root>
1388
+ * EOF
1389
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
1390
+ * # => []
1391
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
1392
+ * # => [#(Namespace:0x3c { href = "http://example.com/child" }),
1393
+ * # #(Namespace:0x50 {
1394
+ * # prefix = "unused",
1395
+ * # href = "http://example.com/unused"
1396
+ * # })]
1397
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
1398
+ * # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
1072
1399
  */
1073
1400
  static VALUE
1074
1401
  namespace_definitions(VALUE rb_node)
@@ -1094,16 +1421,35 @@ namespace_definitions(VALUE rb_node)
1094
1421
  }
1095
1422
 
1096
1423
  /*
1097
- * call-seq:
1098
- * namespace_scopes()
1424
+ * :call-seq:
1425
+ * namespace_scopes() → Array<Nokogiri::XML::Namespace>
1099
1426
  *
1100
- * returns namespaces in scope for self -- those defined on self element
1101
- * directly or any ancestor node -- as an array of Namespace objects. Default
1102
- * namespaces ("xmlns=" style) for self are included in this array; Default
1103
- * namespaces for ancestors, however, are not. See also #namespaces
1427
+ * [Returns] Array of all the Namespaces on this node and its ancestors.
1428
+ *
1429
+ * See also #namespaces
1430
+ *
1431
+ * *Example:*
1432
+ *
1433
+ * doc = Nokogiri::XML(<<~EOF)
1434
+ * <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
1435
+ * <first/>
1436
+ * <second xmlns="http://example.com/child"/>
1437
+ * <third xmlns:foo="http://example.com/foo"/>
1438
+ * </root>
1439
+ * EOF
1440
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
1441
+ * # => [#(Namespace:0x3c { href = "http://example.com/root" }),
1442
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1443
+ * doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
1444
+ * # => [#(Namespace:0x64 { href = "http://example.com/child" }),
1445
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1446
+ * doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
1447
+ * # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
1448
+ * # #(Namespace:0x3c { href = "http://example.com/root" }),
1449
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1104
1450
  */
1105
1451
  static VALUE
1106
- namespace_scopes(VALUE rb_node)
1452
+ rb_xml_node_namespace_scopes(VALUE rb_node)
1107
1453
  {
1108
1454
  xmlNodePtr c_node ;
1109
1455
  xmlNsPtr *namespaces;
@@ -1163,30 +1509,6 @@ set_native_content(VALUE self, VALUE content)
1163
1509
  return content;
1164
1510
  }
1165
1511
 
1166
- /*
1167
- * call-seq:
1168
- * content
1169
- *
1170
- * Returns the plaintext content for this Node. Note that entities will always
1171
- * be expanded in the returned string.
1172
- */
1173
- static VALUE
1174
- get_native_content(VALUE self)
1175
- {
1176
- xmlNodePtr node;
1177
- xmlChar *content;
1178
-
1179
- Data_Get_Struct(self, xmlNode, node);
1180
-
1181
- content = xmlNodeGetContent(node);
1182
- if (content) {
1183
- VALUE rval = NOKOGIRI_STR_NEW2(content);
1184
- xmlFree(content);
1185
- return rval;
1186
- }
1187
- return Qnil;
1188
- }
1189
-
1190
1512
  /*
1191
1513
  * call-seq:
1192
1514
  * lang=
@@ -1297,7 +1619,7 @@ get_name(VALUE self)
1297
1619
  * Returns the path associated with this Node
1298
1620
  */
1299
1621
  static VALUE
1300
- noko_xml_node_path(VALUE rb_node)
1622
+ rb_xml_node_path(VALUE rb_node)
1301
1623
  {
1302
1624
  xmlNodePtr c_node;
1303
1625
  xmlChar *c_path ;
@@ -1376,18 +1698,39 @@ native_write_to(
1376
1698
  }
1377
1699
 
1378
1700
  /*
1379
- * call-seq:
1380
- * line
1701
+ * :call-seq:
1702
+ * line() → Integer
1703
+ *
1704
+ * [Returns] The line number of this Node.
1705
+ *
1706
+ * ---
1707
+ *
1708
+ * <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
1709
+ *
1710
+ * Semantic differences:
1711
+ * - The CRuby method reflects the node's line number <i>in the parsed string</i>
1712
+ * - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
1713
+ * corrections have been applied
1714
+ *
1715
+ * Performance differences:
1716
+ * - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
1717
+ * (constant time)
1718
+ * - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
1719
+ * time, where n is the number of nodes before/above the element in the DOM)
1381
1720
  *
1382
- * Returns the line for this Node
1721
+ * If you'd like to help improve the JRuby implementation, please review these issues and reach out
1722
+ * to the maintainers:
1723
+ * - https://github.com/sparklemotion/nokogiri/issues/1223
1724
+ * - https://github.com/sparklemotion/nokogiri/pull/2177
1725
+ * - https://github.com/sparklemotion/nokogiri/issues/2380
1383
1726
  */
1384
1727
  static VALUE
1385
- line(VALUE self)
1728
+ rb_xml_node_line(VALUE rb_node)
1386
1729
  {
1387
- xmlNodePtr node;
1388
- Data_Get_Struct(self, xmlNode, node);
1730
+ xmlNodePtr c_node;
1731
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1389
1732
 
1390
- return INT2NUM(xmlGetLineNo(node));
1733
+ return INT2NUM(xmlGetLineNo(c_node));
1391
1734
  }
1392
1735
 
1393
1736
  /*
@@ -1397,90 +1740,56 @@ line(VALUE self)
1397
1740
  * Sets the line for this Node. num must be less than 65535.
1398
1741
  */
1399
1742
  static VALUE
1400
- set_line(VALUE self, VALUE num)
1743
+ rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
1401
1744
  {
1402
- xmlNodePtr node;
1403
- int value = NUM2INT(num);
1404
-
1405
- Data_Get_Struct(self, xmlNode, node);
1406
- if (value < 65535) {
1407
- node->line = value;
1408
- }
1409
-
1410
- return num;
1411
- }
1412
-
1413
- /*
1414
- * call-seq:
1415
- * add_namespace_definition(prefix, href)
1416
- *
1417
- * Adds a namespace definition with +prefix+ using +href+ value. The result is
1418
- * as if parsed XML for this node had included an attribute
1419
- * 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
1420
- * added by passing 'nil' for prefix. Namespaces added this way will not
1421
- * show up in #attributes, but they will be included as an xmlns attribute
1422
- * when the node is serialized to XML.
1423
- */
1424
- static VALUE
1425
- add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
1426
- {
1427
- xmlNodePtr c_node, element;
1428
- xmlNsPtr c_namespace;
1429
- const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
1745
+ xmlNodePtr c_node;
1746
+ int line_number = NUM2INT(rb_line_number);
1430
1747
 
1431
1748
  Data_Get_Struct(rb_node, xmlNode, c_node);
1432
- element = c_node ;
1433
1749
 
1434
- c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
1435
-
1436
- if (!c_namespace) {
1437
- if (c_node->type != XML_ELEMENT_NODE) {
1438
- element = c_node->parent;
1750
+ // libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
1751
+ // search for "psvi" in SAX2.c and tree.c to learn more.
1752
+ if (line_number < 65535) {
1753
+ c_node->line = (short) line_number;
1754
+ } else {
1755
+ c_node->line = 65535;
1756
+ if (c_node->type == XML_TEXT_NODE) {
1757
+ c_node->psvi = (void *)(ptrdiff_t) line_number;
1439
1758
  }
1440
- c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
1441
- }
1442
-
1443
- if (!c_namespace) {
1444
- return Qnil ;
1445
- }
1446
-
1447
- if (NIL_P(rb_prefix) || c_node != element) {
1448
- xmlSetNs(c_node, c_namespace);
1449
1759
  }
1450
1760
 
1451
- return noko_xml_namespace_wrap(c_namespace, c_node->doc);
1761
+ return rb_line_number;
1452
1762
  }
1453
1763
 
1454
- /*
1455
- * @overload new(name, document)
1456
- * Create a new node with +name+ sharing GC lifecycle with +document+.
1457
- * @param name [String]
1458
- * @param document [Nokogiri::XML::Document]
1459
- * @yieldparam node [Nokogiri::XML::Node]
1460
- * @return [Nokogiri::XML::Node]
1461
- * @see Nokogiri::XML::Node#initialize
1462
- */
1764
+ /* :nodoc: documented in lib/nokogiri/xml/node.rb */
1463
1765
  static VALUE
1464
1766
  rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
1465
1767
  {
1466
- xmlDocPtr doc;
1467
- xmlNodePtr node;
1468
- VALUE name;
1469
- VALUE document;
1768
+ xmlNodePtr c_document_node;
1769
+ xmlNodePtr c_node;
1770
+ VALUE rb_name;
1771
+ VALUE rb_document_node;
1470
1772
  VALUE rest;
1471
1773
  VALUE rb_node;
1472
1774
 
1473
- rb_scan_args(argc, argv, "2*", &name, &document, &rest);
1775
+ rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
1474
1776
 
1475
- Data_Get_Struct(document, xmlDoc, doc);
1777
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
1778
+ rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
1779
+ }
1780
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
1781
+ // TODO: deprecate allowing Node
1782
+ rb_warn("Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in a future release of Nokogiri.");
1783
+ }
1784
+ Data_Get_Struct(rb_document_node, xmlNode, c_document_node);
1476
1785
 
1477
- node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(name));
1478
- node->doc = doc->doc;
1479
- noko_xml_document_pin_node(node);
1786
+ c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
1787
+ c_node->doc = c_document_node->doc;
1788
+ noko_xml_document_pin_node(c_node);
1480
1789
 
1481
1790
  rb_node = noko_xml_node_wrap(
1482
1791
  klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1483
- node
1792
+ c_node
1484
1793
  );
1485
1794
  rb_obj_call_init(rb_node, argc, argv);
1486
1795
 
@@ -1614,9 +1923,7 @@ in_context(VALUE self, VALUE _str, VALUE _options)
1614
1923
  */
1615
1924
  child_iter = node->doc->children ;
1616
1925
  while (child_iter) {
1617
- if (child_iter->parent != (xmlNodePtr)node->doc) {
1618
- child_iter->parent = (xmlNodePtr)node->doc;
1619
- }
1926
+ child_iter->parent = (xmlNodePtr)node->doc;
1620
1927
  child_iter = child_iter->next;
1621
1928
  }
1622
1929
 
@@ -1674,7 +1981,7 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1674
1981
  VALUE rb_document, rb_node_cache, rb_node;
1675
1982
  nokogiriTuplePtr node_has_a_document;
1676
1983
  xmlDocPtr c_doc;
1677
- void (*mark_method)(xmlNodePtr) = NULL ;
1984
+ void (*f_mark)(xmlNodePtr) = NULL ;
1678
1985
 
1679
1986
  assert(c_node);
1680
1987
 
@@ -1736,9 +2043,9 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1736
2043
  }
1737
2044
  }
1738
2045
 
1739
- mark_method = node_has_a_document ? mark : NULL ;
2046
+ f_mark = node_has_a_document ? _xml_node_mark : NULL ;
1740
2047
 
1741
- rb_node = Data_Wrap_Struct(rb_class, mark_method, debug_node_dealloc, c_node) ;
2048
+ rb_node = Data_Wrap_Struct(rb_class, f_mark, _xml_node_dealloc, c_node) ;
1742
2049
  c_node->_private = (void *)rb_node;
1743
2050
 
1744
2051
  if (node_has_a_document) {
@@ -1779,61 +2086,59 @@ noko_init_xml_node()
1779
2086
 
1780
2087
  rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
1781
2088
 
1782
- rb_define_method(cNokogiriXmlNode, "add_namespace_definition", add_namespace_definition, 2);
2089
+ rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
2090
+ rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
2091
+ rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
2092
+ rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
2093
+ rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
2094
+ rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
2095
+ rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
2096
+ rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
2097
+ rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
2098
+ rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
2099
+ rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
2100
+ rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2101
+ rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
2102
+ rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
2103
+ rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
2104
+ rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
2105
+ rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
2106
+ rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
2107
+ rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
2108
+ rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
2109
+ rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
2110
+ rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
2111
+ rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
2112
+ rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
2113
+ rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
2114
+ rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
2115
+ rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
2116
+ rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
2117
+ rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
2118
+ rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
1783
2119
  rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
1784
- rb_define_method(cNokogiriXmlNode, "document", document, 0);
1785
2120
  rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
2121
+ rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
1786
2122
  rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
1787
- rb_define_method(cNokogiriXmlNode, "child", child, 0);
1788
- rb_define_method(cNokogiriXmlNode, "first_element_child", first_element_child, 0);
1789
- rb_define_method(cNokogiriXmlNode, "last_element_child", last_element_child, 0);
1790
- rb_define_method(cNokogiriXmlNode, "children", children, 0);
1791
- rb_define_method(cNokogiriXmlNode, "element_children", element_children, 0);
1792
- rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
1793
- rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
1794
- rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
2123
+ rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
2124
+ rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
1795
2125
  rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
1796
- rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
1797
- rb_define_method(cNokogiriXmlNode, "path", noko_xml_node_path, 0);
1798
- rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
1799
- rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
1800
- rb_define_method(cNokogiriXmlNode, "blank?", blank_eh, 0);
1801
- rb_define_method(cNokogiriXmlNode, "attribute_nodes", attribute_nodes, 0);
1802
- rb_define_method(cNokogiriXmlNode, "attribute", attr, 1);
1803
- rb_define_method(cNokogiriXmlNode, "attribute_with_ns", attribute_with_ns, 2);
1804
- rb_define_method(cNokogiriXmlNode, "namespace", noko_xml_node_namespace, 0);
1805
- rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
1806
- rb_define_method(cNokogiriXmlNode, "namespace_scopes", namespace_scopes, 0);
1807
- rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
1808
- rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2126
+ rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
1809
2127
  rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
1810
- rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
1811
- rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
1812
- rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
1813
- rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
1814
- rb_define_method(cNokogiriXmlNode, "pointer_id", pointer_id, 0);
1815
- rb_define_method(cNokogiriXmlNode, "line", line, 0);
1816
- rb_define_method(cNokogiriXmlNode, "line=", set_line, 1);
1817
- rb_define_method(cNokogiriXmlNode, "content", get_native_content, 0);
1818
- rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
1819
- rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
1820
- rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
1821
2128
 
1822
- rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
1823
- rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
1824
2129
  rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
1825
- rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
1826
2130
  rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
1827
- rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
2131
+ rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
2132
+ rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
1828
2133
  rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
1829
- rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
1830
2134
  rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
2135
+ rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
2136
+ rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
2137
+ rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
2138
+ rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
1831
2139
  rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
1832
2140
  rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
1833
- rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
1834
2141
 
1835
2142
  id_decorate = rb_intern("decorate");
1836
2143
  id_decorate_bang = rb_intern("decorate!");
1837
2144
  }
1838
-
1839
- /* vim: set noet sw=4 sws=4 */