nokogiri 1.12.2-java → 1.13.0-java

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 (111) 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/java/nokogiri/Html4SaxPushParser.java +14 -19
  7. data/ext/java/nokogiri/XmlDocumentFragment.java +4 -15
  8. data/ext/java/nokogiri/XmlNamespace.java +0 -8
  9. data/ext/java/nokogiri/XmlNode.java +32 -16
  10. data/ext/java/nokogiri/XmlNodeSet.java +0 -4
  11. data/ext/java/nokogiri/XmlReader.java +12 -0
  12. data/ext/java/nokogiri/XmlSaxParserContext.java +31 -93
  13. data/ext/java/nokogiri/XmlSaxPushParser.java +17 -25
  14. data/ext/java/nokogiri/XmlSchema.java +1 -1
  15. data/ext/java/nokogiri/internals/NokogiriEntityResolver.java +1 -1
  16. data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +29 -8
  17. data/ext/java/nokogiri/internals/NokogiriHandler.java +6 -24
  18. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +9 -8
  19. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +10 -9
  20. data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +7 -6
  21. data/ext/java/nokogiri/internals/SaveContextVisitor.java +2 -0
  22. data/ext/java/nokogiri/internals/XmlDomParserContext.java +16 -25
  23. data/ext/nokogiri/extconf.rb +51 -35
  24. data/ext/nokogiri/gumbo.c +11 -11
  25. data/ext/nokogiri/html4_element_description.c +1 -1
  26. data/ext/nokogiri/html4_sax_parser_context.c +2 -1
  27. data/ext/nokogiri/nokogiri.c +1 -1
  28. data/ext/nokogiri/xml_document.c +36 -36
  29. data/ext/nokogiri/xml_document_fragment.c +0 -2
  30. data/ext/nokogiri/xml_dtd.c +2 -2
  31. data/ext/nokogiri/xml_encoding_handler.c +25 -11
  32. data/ext/nokogiri/xml_namespace.c +2 -2
  33. data/ext/nokogiri/xml_node.c +647 -335
  34. data/ext/nokogiri/xml_reader.c +37 -11
  35. data/ext/nokogiri/xml_xpath_context.c +72 -49
  36. data/lib/nokogiri/class_resolver.rb +67 -0
  37. data/lib/nokogiri/css/node.rb +9 -8
  38. data/lib/nokogiri/css/parser.rb +11 -3
  39. data/lib/nokogiri/css/parser.y +10 -2
  40. data/lib/nokogiri/css/parser_extras.rb +20 -20
  41. data/lib/nokogiri/css/syntax_error.rb +1 -0
  42. data/lib/nokogiri/css/tokenizer.rb +2 -1
  43. data/lib/nokogiri/css/tokenizer.rex +2 -1
  44. data/lib/nokogiri/css/xpath_visitor.rb +174 -75
  45. data/lib/nokogiri/css.rb +38 -6
  46. data/lib/nokogiri/decorators/slop.rb +8 -7
  47. data/lib/nokogiri/extension.rb +1 -1
  48. data/lib/nokogiri/gumbo.rb +1 -0
  49. data/lib/nokogiri/html.rb +16 -10
  50. data/lib/nokogiri/html4/builder.rb +1 -0
  51. data/lib/nokogiri/html4/document.rb +84 -75
  52. data/lib/nokogiri/html4/document_fragment.rb +11 -7
  53. data/lib/nokogiri/html4/element_description.rb +1 -0
  54. data/lib/nokogiri/html4/element_description_defaults.rb +426 -520
  55. data/lib/nokogiri/html4/entity_lookup.rb +2 -1
  56. data/lib/nokogiri/html4/sax/parser.rb +2 -1
  57. data/lib/nokogiri/html4/sax/parser_context.rb +1 -0
  58. data/lib/nokogiri/html4/sax/push_parser.rb +7 -7
  59. data/lib/nokogiri/html4.rb +11 -5
  60. data/lib/nokogiri/html5/document.rb +24 -10
  61. data/lib/nokogiri/html5/document_fragment.rb +5 -2
  62. data/lib/nokogiri/html5/node.rb +6 -3
  63. data/lib/nokogiri/html5.rb +68 -64
  64. data/lib/nokogiri/jruby/dependencies.rb +10 -9
  65. data/lib/nokogiri/nokogiri.jar +0 -0
  66. data/lib/nokogiri/syntax_error.rb +1 -0
  67. data/lib/nokogiri/version/constant.rb +2 -1
  68. data/lib/nokogiri/version/info.rb +19 -13
  69. data/lib/nokogiri/version.rb +1 -0
  70. data/lib/nokogiri/xml/attr.rb +5 -3
  71. data/lib/nokogiri/xml/attribute_decl.rb +2 -1
  72. data/lib/nokogiri/xml/builder.rb +69 -31
  73. data/lib/nokogiri/xml/cdata.rb +2 -1
  74. data/lib/nokogiri/xml/character_data.rb +1 -0
  75. data/lib/nokogiri/xml/document.rb +178 -96
  76. data/lib/nokogiri/xml/document_fragment.rb +41 -38
  77. data/lib/nokogiri/xml/dtd.rb +3 -2
  78. data/lib/nokogiri/xml/element_content.rb +1 -0
  79. data/lib/nokogiri/xml/element_decl.rb +2 -1
  80. data/lib/nokogiri/xml/entity_decl.rb +3 -2
  81. data/lib/nokogiri/xml/entity_reference.rb +1 -0
  82. data/lib/nokogiri/xml/namespace.rb +2 -0
  83. data/lib/nokogiri/xml/node/save_options.rb +7 -4
  84. data/lib/nokogiri/xml/node.rb +512 -348
  85. data/lib/nokogiri/xml/node_set.rb +46 -54
  86. data/lib/nokogiri/xml/notation.rb +12 -0
  87. data/lib/nokogiri/xml/parse_options.rb +11 -7
  88. data/lib/nokogiri/xml/pp/character_data.rb +8 -6
  89. data/lib/nokogiri/xml/pp/node.rb +24 -26
  90. data/lib/nokogiri/xml/pp.rb +1 -0
  91. data/lib/nokogiri/xml/processing_instruction.rb +2 -1
  92. data/lib/nokogiri/xml/reader.rb +17 -19
  93. data/lib/nokogiri/xml/relax_ng.rb +1 -0
  94. data/lib/nokogiri/xml/sax/document.rb +20 -19
  95. data/lib/nokogiri/xml/sax/parser.rb +36 -34
  96. data/lib/nokogiri/xml/sax/parser_context.rb +7 -3
  97. data/lib/nokogiri/xml/sax/push_parser.rb +5 -5
  98. data/lib/nokogiri/xml/sax.rb +1 -0
  99. data/lib/nokogiri/xml/schema.rb +7 -6
  100. data/lib/nokogiri/xml/searchable.rb +42 -22
  101. data/lib/nokogiri/xml/syntax_error.rb +4 -4
  102. data/lib/nokogiri/xml/text.rb +1 -0
  103. data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
  104. data/lib/nokogiri/xml/xpath.rb +12 -0
  105. data/lib/nokogiri/xml/xpath_context.rb +2 -3
  106. data/lib/nokogiri/xml.rb +3 -3
  107. data/lib/nokogiri/xslt/stylesheet.rb +1 -0
  108. data/lib/nokogiri/xslt.rb +3 -2
  109. data/lib/nokogiri.rb +19 -16
  110. data/lib/xsd/xmlparser/nokogiri.rb +25 -24
  111. metadata +102 -30
@@ -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
  {
@@ -69,6 +71,13 @@ relink_namespace(xmlNodePtr reparented)
69
71
  /* Avoid segv when relinking against unlinked nodes. */
70
72
  if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
71
73
 
74
+ /* Make sure that our reparented node has the correct namespaces */
75
+ if (!reparented->ns &&
76
+ (reparented->doc != (xmlDocPtr)reparented->parent) &&
77
+ (rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
78
+ xmlSetNs(reparented, reparented->parent->ns);
79
+ }
80
+
72
81
  /* Search our parents for an existing definition */
73
82
  if (reparented->nsDef) {
74
83
  xmlNsPtr curr = reparented->nsDef;
@@ -136,7 +145,9 @@ relink_namespace(xmlNodePtr reparented)
136
145
  }
137
146
  }
138
147
 
139
- /* :nodoc: */
148
+
149
+ /* internal function meant to wrap xmlReplaceNode
150
+ and fix some issues we have with libxml2 merging nodes */
140
151
  static xmlNodePtr
141
152
  xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
142
153
  {
@@ -161,7 +172,18 @@ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
161
172
  return retval ;
162
173
  }
163
174
 
164
- /* :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
+
165
187
  static VALUE
166
188
  reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
167
189
  {
@@ -304,7 +326,7 @@ ok:
304
326
  * issue #391, where new node's prefix may become the string "default"
305
327
  * see libxml2 tree.c xmlNewReconciliedNs which implements this behavior.
306
328
  */
307
- xmlFree((xmlChar *)reparentee->ns->prefix);
329
+ xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix));
308
330
  reparentee->ns->prefix = NULL;
309
331
  }
310
332
  }
@@ -350,25 +372,397 @@ ok:
350
372
  * adjacent text nodes.
351
373
  */
352
374
  DATA_PTR(reparentee_obj) = reparented ;
353
-
354
- relink_namespace(reparented);
355
-
356
375
  reparented_obj = noko_xml_node_wrap(Qnil, reparented);
357
376
 
358
377
  rb_funcall(reparented_obj, id_decorate_bang, 0);
359
378
 
379
+ /* if we've created a cycle, raise an exception */
380
+ raise_if_ancestor_of_self(reparented);
381
+
382
+ relink_namespace(reparented);
383
+
360
384
  return reparented_obj ;
361
385
  }
362
386
 
387
+ // :startdoc:
363
388
 
364
389
  /*
365
- * call-seq:
366
- * 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"
433
+ *
434
+ */
435
+ static VALUE
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
367
579
  *
368
- * Get the document for this Node
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
369
656
  */
370
657
  static VALUE
371
- document(VALUE self)
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)
372
766
  {
373
767
  xmlNodePtr node;
374
768
  Data_Get_Struct(self, xmlNode, node);
@@ -376,13 +770,14 @@ document(VALUE self)
376
770
  }
377
771
 
378
772
  /*
379
- * call-seq:
380
- * pointer_id
773
+ * :call-seq: pointer_id() → Integer
381
774
  *
382
- * 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.
383
778
  */
384
779
  static VALUE
385
- pointer_id(VALUE self)
780
+ rb_xml_node_pointer_id(VALUE self)
386
781
  {
387
782
  xmlNodePtr node;
388
783
  Data_Get_Struct(self, xmlNode, node);
@@ -391,8 +786,7 @@ pointer_id(VALUE self)
391
786
  }
392
787
 
393
788
  /*
394
- * call-seq:
395
- * encode_special_chars(string)
789
+ * :call-seq: encode_special_chars(string) → String
396
790
  *
397
791
  * Encode any special characters in +string+
398
792
  */
@@ -416,8 +810,8 @@ encode_special_chars(VALUE self, VALUE string)
416
810
  }
417
811
 
418
812
  /*
419
- * call-seq:
420
- * create_internal_subset(name, external_id, system_id)
813
+ * :call-seq:
814
+ * create_internal_subset(name, external_id, system_id)
421
815
  *
422
816
  * Create the internal subset of a document.
423
817
  *
@@ -455,8 +849,8 @@ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
455
849
  }
456
850
 
457
851
  /*
458
- * call-seq:
459
- * create_external_subset(name, external_id, system_id)
852
+ * :call-seq:
853
+ * create_external_subset(name, external_id, system_id)
460
854
  *
461
855
  * Create an external subset
462
856
  */
@@ -488,8 +882,8 @@ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
488
882
  }
489
883
 
490
884
  /*
491
- * call-seq:
492
- * external_subset
885
+ * :call-seq:
886
+ * external_subset()
493
887
  *
494
888
  * Get the external subset
495
889
  */
@@ -513,8 +907,8 @@ external_subset(VALUE self)
513
907
  }
514
908
 
515
909
  /*
516
- * call-seq:
517
- * internal_subset
910
+ * :call-seq:
911
+ * internal_subset()
518
912
  *
519
913
  * Get the internal subset
520
914
  */
@@ -538,16 +932,19 @@ internal_subset(VALUE self)
538
932
  }
539
933
 
540
934
  /*
541
- * call-seq:
542
- * dup
543
- * dup(depth)
544
- * 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
545
939
  *
546
940
  * Copy this node.
547
- * An optional depth may be passed in. 0 is a shallow copy, 1 (the default) is a deep copy.
548
- * An optional new_parent_doc may also be passed in, which will be the new
549
- * node's parent document. Defaults to the current node's document.
550
- * 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
551
948
  */
552
949
  static VALUE
553
950
  duplicate_node(int argc, VALUE *argv, VALUE self)
@@ -582,8 +979,8 @@ duplicate_node(int argc, VALUE *argv, VALUE self)
582
979
  }
583
980
 
584
981
  /*
585
- * call-seq:
586
- * unlink
982
+ * :call-seq:
983
+ * unlink() → self
587
984
  *
588
985
  * Unlink this node from its current context.
589
986
  */
@@ -597,19 +994,6 @@ unlink_node(VALUE self)
597
994
  return self;
598
995
  }
599
996
 
600
- /*
601
- * call-seq:
602
- * blank?
603
- *
604
- * Is this node blank?
605
- */
606
- static VALUE
607
- blank_eh(VALUE self)
608
- {
609
- xmlNodePtr node;
610
- Data_Get_Struct(self, xmlNode, node);
611
- return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
612
- }
613
997
 
614
998
  /*
615
999
  * call-seq:
@@ -704,53 +1088,27 @@ replace(VALUE self, VALUE new_node)
704
1088
  }
705
1089
 
706
1090
  /*
707
- * call-seq:
708
- * children
1091
+ * :call-seq:
1092
+ * element_children() → NodeSet
1093
+ * elements() → NodeSet
709
1094
  *
710
- * Get the list of children for this node as a NodeSet
711
- */
712
- static VALUE
713
- children(VALUE self)
714
- {
715
- xmlNodePtr node;
716
- xmlNodePtr child;
717
- xmlNodeSetPtr set;
718
- VALUE document;
719
- VALUE node_set;
720
-
721
- Data_Get_Struct(self, xmlNode, node);
722
-
723
- child = node->children;
724
- set = xmlXPathNodeSetCreate(child);
725
-
726
- document = DOC_RUBY_OBJECT(node->doc);
727
-
728
- if (!child) { return noko_xml_node_set_wrap(set, document); }
729
-
730
- child = child->next;
731
- while (NULL != child) {
732
- xmlXPathNodeSetAddUnique(set, child);
733
- child = child->next;
734
- }
735
-
736
- node_set = noko_xml_node_set_wrap(set, document);
737
-
738
- return node_set;
739
- }
740
-
741
- /*
742
- * call-seq:
743
- * 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.
744
1098
  *
745
- * Get the list of children for this node as a NodeSet. All nodes will be
746
- * element nodes.
1099
+ * *Example:*
747
1100
  *
748
- * Example:
1101
+ * Note that #children returns the Text node "hello" while #element_children does not.
749
1102
  *
750
- * @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">]>]
751
1109
  */
752
1110
  static VALUE
753
- element_children(VALUE self)
1111
+ rb_xml_node_element_children(VALUE self)
754
1112
  {
755
1113
  xmlNodePtr node;
756
1114
  xmlNodePtr child;
@@ -779,35 +1137,22 @@ element_children(VALUE self)
779
1137
  }
780
1138
 
781
1139
  /*
782
- * call-seq:
783
- * child
1140
+ * :call-seq:
1141
+ * first_element_child() → Node
784
1142
  *
785
- * Returns the child node
786
- */
787
- static VALUE
788
- child(VALUE self)
789
- {
790
- xmlNodePtr node, child;
791
- Data_Get_Struct(self, xmlNode, node);
792
-
793
- child = node->children;
794
- if (!child) { return Qnil; }
795
-
796
- return noko_xml_node_wrap(Qnil, child);
797
- }
798
-
799
- /*
800
- * call-seq:
801
- * first_element_child
1143
+ * [Returns] The first child Node that is an element.
802
1144
  *
803
- * Returns the first child node of this node that is an element.
1145
+ * *Example:*
804
1146
  *
805
- * Example:
1147
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
1148
+ * returned.
806
1149
  *
807
- * @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")] })
808
1153
  */
809
1154
  static VALUE
810
- first_element_child(VALUE self)
1155
+ rb_xml_node_first_element_child(VALUE self)
811
1156
  {
812
1157
  xmlNodePtr node, child;
813
1158
  Data_Get_Struct(self, xmlNode, node);
@@ -819,17 +1164,22 @@ first_element_child(VALUE self)
819
1164
  }
820
1165
 
821
1166
  /*
822
- * call-seq:
823
- * last_element_child
1167
+ * :call-seq:
1168
+ * last_element_child() → Node
1169
+ *
1170
+ * [Returns] The last child Node that is an element.
824
1171
  *
825
- * Returns the last child node of this node that is an element.
1172
+ * *Example:*
826
1173
  *
827
- * Example:
1174
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
1175
+ * element is returned.
828
1176
  *
829
- * @doc.root.last_element_child.element? # => true
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")] })
830
1180
  */
831
1181
  static VALUE
832
- last_element_child(VALUE self)
1182
+ rb_xml_node_last_element_child(VALUE self)
833
1183
  {
834
1184
  xmlNodePtr node, child;
835
1185
  Data_Get_Struct(self, xmlNode, node);
@@ -934,7 +1284,7 @@ get(VALUE self, VALUE rattribute)
934
1284
  Data_Get_Struct(self, xmlNode, node);
935
1285
  attribute = xmlCharStrdup(StringValueCStr(rattribute));
936
1286
 
937
- colon = (xmlChar *)(uintptr_t)xmlStrchr(attribute, (const xmlChar)':');
1287
+ colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':'));
938
1288
  if (colon) {
939
1289
  /* split the attribute string into separate prefix and name by
940
1290
  * null-terminating the prefix at the colon */
@@ -985,67 +1335,29 @@ set_namespace(VALUE self, VALUE namespace)
985
1335
  }
986
1336
 
987
1337
  /*
988
- * call-seq:
989
- * attribute(name)
1338
+ * :call-seq:
1339
+ * namespace() → Namespace
990
1340
  *
991
- * Get the attribute node with +name+
992
- */
993
- static VALUE
994
- attr(VALUE self, VALUE name)
995
- {
996
- xmlNodePtr node;
997
- xmlAttrPtr prop;
998
- Data_Get_Struct(self, xmlNode, node);
999
- prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
1000
-
1001
- if (! prop) { return Qnil; }
1002
- return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
1003
- }
1004
-
1005
- /*
1006
- * call-seq:
1007
- * attribute_with_ns(name, namespace)
1341
+ * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
1008
1342
  *
1009
- * Get the attribute node with +name+ and +namespace+
1010
- */
1011
- static VALUE
1012
- attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
1013
- {
1014
- xmlNodePtr node;
1015
- xmlAttrPtr prop;
1016
- Data_Get_Struct(self, xmlNode, node);
1017
- prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
1018
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
1019
-
1020
- if (! prop) { return Qnil; }
1021
- return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
1022
- }
1023
-
1024
- /*
1025
- * @overload attribute_nodes()
1026
- * Get the attributes for a Node
1027
- * @return [Array<Nokogiri::XML::Attr>] containing the Node's attributes.
1028
- */
1029
- static VALUE
1030
- attribute_nodes(VALUE rb_node)
1031
- {
1032
- xmlNodePtr c_node;
1033
-
1034
- Data_Get_Struct(rb_node, xmlNode, c_node);
1035
-
1036
- return noko_xml_node_attrs(c_node);
1037
- }
1038
-
1039
-
1040
- /*
1041
- * call-seq:
1042
- * namespace()
1343
+ * *Example:*
1043
1344
  *
1044
- * returns the namespace of the element or attribute node as a Namespace
1045
- * 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" })
1046
1358
  */
1047
1359
  static VALUE
1048
- noko_xml_node_namespace(VALUE rb_node)
1360
+ rb_xml_node_namespace(VALUE rb_node)
1049
1361
  {
1050
1362
  xmlNodePtr c_node ;
1051
1363
  Data_Get_Struct(rb_node, xmlNode, c_node);
@@ -1058,10 +1370,32 @@ noko_xml_node_namespace(VALUE rb_node)
1058
1370
  }
1059
1371
 
1060
1372
  /*
1061
- * call-seq:
1062
- * 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.
1063
1379
  *
1064
- * 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=").
1380
+ * *Example:*
1381
+ *
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" })]
1065
1399
  */
1066
1400
  static VALUE
1067
1401
  namespace_definitions(VALUE rb_node)
@@ -1087,16 +1421,35 @@ namespace_definitions(VALUE rb_node)
1087
1421
  }
1088
1422
 
1089
1423
  /*
1090
- * call-seq:
1091
- * namespace_scopes()
1424
+ * :call-seq:
1425
+ * namespace_scopes() → Array<Nokogiri::XML::Namespace>
1426
+ *
1427
+ * [Returns] Array of all the Namespaces on this node and its ancestors.
1428
+ *
1429
+ * See also #namespaces
1430
+ *
1431
+ * *Example:*
1092
1432
  *
1093
- * returns namespaces in scope for self -- those defined on self element
1094
- * directly or any ancestor node -- as an array of Namespace objects. Default
1095
- * namespaces ("xmlns=" style) for self are included in this array; Default
1096
- * namespaces for ancestors, however, are not. See also #namespaces
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" })]
1097
1450
  */
1098
1451
  static VALUE
1099
- namespace_scopes(VALUE rb_node)
1452
+ rb_xml_node_namespace_scopes(VALUE rb_node)
1100
1453
  {
1101
1454
  xmlNodePtr c_node ;
1102
1455
  xmlNsPtr *namespaces;
@@ -1156,30 +1509,6 @@ set_native_content(VALUE self, VALUE content)
1156
1509
  return content;
1157
1510
  }
1158
1511
 
1159
- /*
1160
- * call-seq:
1161
- * content
1162
- *
1163
- * Returns the plaintext content for this Node. Note that entities will always
1164
- * be expanded in the returned string.
1165
- */
1166
- static VALUE
1167
- get_native_content(VALUE self)
1168
- {
1169
- xmlNodePtr node;
1170
- xmlChar *content;
1171
-
1172
- Data_Get_Struct(self, xmlNode, node);
1173
-
1174
- content = xmlNodeGetContent(node);
1175
- if (content) {
1176
- VALUE rval = NOKOGIRI_STR_NEW2(content);
1177
- xmlFree(content);
1178
- return rval;
1179
- }
1180
- return Qnil;
1181
- }
1182
-
1183
1512
  /*
1184
1513
  * call-seq:
1185
1514
  * lang=
@@ -1290,7 +1619,7 @@ get_name(VALUE self)
1290
1619
  * Returns the path associated with this Node
1291
1620
  */
1292
1621
  static VALUE
1293
- noko_xml_node_path(VALUE rb_node)
1622
+ rb_xml_node_path(VALUE rb_node)
1294
1623
  {
1295
1624
  xmlNodePtr c_node;
1296
1625
  xmlChar *c_path ;
@@ -1369,18 +1698,39 @@ native_write_to(
1369
1698
  }
1370
1699
 
1371
1700
  /*
1372
- * call-seq:
1373
- * 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
1374
1714
  *
1375
- * Returns the line for this Node
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)
1720
+ *
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
1376
1726
  */
1377
1727
  static VALUE
1378
- line(VALUE self)
1728
+ rb_xml_node_line(VALUE rb_node)
1379
1729
  {
1380
- xmlNodePtr node;
1381
- Data_Get_Struct(self, xmlNode, node);
1730
+ xmlNodePtr c_node;
1731
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1382
1732
 
1383
- return INT2NUM(xmlGetLineNo(node));
1733
+ return INT2NUM(xmlGetLineNo(c_node));
1384
1734
  }
1385
1735
 
1386
1736
  /*
@@ -1390,90 +1740,56 @@ line(VALUE self)
1390
1740
  * Sets the line for this Node. num must be less than 65535.
1391
1741
  */
1392
1742
  static VALUE
1393
- set_line(VALUE self, VALUE num)
1394
- {
1395
- xmlNodePtr node;
1396
- int value = NUM2INT(num);
1397
-
1398
- Data_Get_Struct(self, xmlNode, node);
1399
- if (value < 65535) {
1400
- node->line = value;
1401
- }
1402
-
1403
- return num;
1404
- }
1405
-
1406
- /*
1407
- * call-seq:
1408
- * add_namespace_definition(prefix, href)
1409
- *
1410
- * Adds a namespace definition with +prefix+ using +href+ value. The result is
1411
- * as if parsed XML for this node had included an attribute
1412
- * 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
1413
- * added by passing 'nil' for prefix. Namespaces added this way will not
1414
- * show up in #attributes, but they will be included as an xmlns attribute
1415
- * when the node is serialized to XML.
1416
- */
1417
- static VALUE
1418
- add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
1743
+ rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
1419
1744
  {
1420
- xmlNodePtr c_node, element;
1421
- xmlNsPtr c_namespace;
1422
- 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);
1423
1747
 
1424
1748
  Data_Get_Struct(rb_node, xmlNode, c_node);
1425
- element = c_node ;
1426
1749
 
1427
- c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
1428
-
1429
- if (!c_namespace) {
1430
- if (c_node->type != XML_ELEMENT_NODE) {
1431
- 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;
1432
1758
  }
1433
- c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
1434
1759
  }
1435
1760
 
1436
- if (!c_namespace) {
1437
- return Qnil ;
1438
- }
1439
-
1440
- if (NIL_P(rb_prefix) || c_node != element) {
1441
- xmlSetNs(c_node, c_namespace);
1442
- }
1443
-
1444
- return noko_xml_namespace_wrap(c_namespace, c_node->doc);
1761
+ return rb_line_number;
1445
1762
  }
1446
1763
 
1447
- /*
1448
- * @overload new(name, document)
1449
- * Create a new node with +name+ sharing GC lifecycle with +document+.
1450
- * @param name [String]
1451
- * @param document [Nokogiri::XML::Document]
1452
- * @yieldparam node [Nokogiri::XML::Node]
1453
- * @return [Nokogiri::XML::Node]
1454
- * @see Nokogiri::XML::Node#initialize
1455
- */
1764
+ /* :nodoc: documented in lib/nokogiri/xml/node.rb */
1456
1765
  static VALUE
1457
1766
  rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
1458
1767
  {
1459
- xmlDocPtr doc;
1460
- xmlNodePtr node;
1461
- VALUE name;
1462
- VALUE document;
1768
+ xmlNodePtr c_document_node;
1769
+ xmlNodePtr c_node;
1770
+ VALUE rb_name;
1771
+ VALUE rb_document_node;
1463
1772
  VALUE rest;
1464
1773
  VALUE rb_node;
1465
1774
 
1466
- rb_scan_args(argc, argv, "2*", &name, &document, &rest);
1775
+ rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
1467
1776
 
1468
- 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);
1469
1785
 
1470
- node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(name));
1471
- node->doc = doc->doc;
1472
- 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);
1473
1789
 
1474
1790
  rb_node = noko_xml_node_wrap(
1475
1791
  klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1476
- node
1792
+ c_node
1477
1793
  );
1478
1794
  rb_obj_call_init(rb_node, argc, argv);
1479
1795
 
@@ -1607,9 +1923,7 @@ in_context(VALUE self, VALUE _str, VALUE _options)
1607
1923
  */
1608
1924
  child_iter = node->doc->children ;
1609
1925
  while (child_iter) {
1610
- if (child_iter->parent != (xmlNodePtr)node->doc) {
1611
- child_iter->parent = (xmlNodePtr)node->doc;
1612
- }
1926
+ child_iter->parent = (xmlNodePtr)node->doc;
1613
1927
  child_iter = child_iter->next;
1614
1928
  }
1615
1929
 
@@ -1667,7 +1981,7 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1667
1981
  VALUE rb_document, rb_node_cache, rb_node;
1668
1982
  nokogiriTuplePtr node_has_a_document;
1669
1983
  xmlDocPtr c_doc;
1670
- void (*mark_method)(xmlNodePtr) = NULL ;
1984
+ void (*f_mark)(xmlNodePtr) = NULL ;
1671
1985
 
1672
1986
  assert(c_node);
1673
1987
 
@@ -1729,9 +2043,9 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1729
2043
  }
1730
2044
  }
1731
2045
 
1732
- mark_method = node_has_a_document ? mark : NULL ;
2046
+ f_mark = node_has_a_document ? _xml_node_mark : NULL ;
1733
2047
 
1734
- 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) ;
1735
2049
  c_node->_private = (void *)rb_node;
1736
2050
 
1737
2051
  if (node_has_a_document) {
@@ -1772,61 +2086,59 @@ noko_init_xml_node()
1772
2086
 
1773
2087
  rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
1774
2088
 
1775
- 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);
1776
2119
  rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
1777
- rb_define_method(cNokogiriXmlNode, "document", document, 0);
1778
2120
  rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
2121
+ rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
1779
2122
  rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
1780
- rb_define_method(cNokogiriXmlNode, "child", child, 0);
1781
- rb_define_method(cNokogiriXmlNode, "first_element_child", first_element_child, 0);
1782
- rb_define_method(cNokogiriXmlNode, "last_element_child", last_element_child, 0);
1783
- rb_define_method(cNokogiriXmlNode, "children", children, 0);
1784
- rb_define_method(cNokogiriXmlNode, "element_children", element_children, 0);
1785
- rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
1786
- rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
1787
- 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);
1788
2125
  rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
1789
- rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
1790
- rb_define_method(cNokogiriXmlNode, "path", noko_xml_node_path, 0);
1791
- rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
1792
- rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
1793
- rb_define_method(cNokogiriXmlNode, "blank?", blank_eh, 0);
1794
- rb_define_method(cNokogiriXmlNode, "attribute_nodes", attribute_nodes, 0);
1795
- rb_define_method(cNokogiriXmlNode, "attribute", attr, 1);
1796
- rb_define_method(cNokogiriXmlNode, "attribute_with_ns", attribute_with_ns, 2);
1797
- rb_define_method(cNokogiriXmlNode, "namespace", noko_xml_node_namespace, 0);
1798
- rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
1799
- rb_define_method(cNokogiriXmlNode, "namespace_scopes", namespace_scopes, 0);
1800
- rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
1801
- rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2126
+ rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
1802
2127
  rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
1803
- rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
1804
- rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
1805
- rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
1806
- rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
1807
- rb_define_method(cNokogiriXmlNode, "pointer_id", pointer_id, 0);
1808
- rb_define_method(cNokogiriXmlNode, "line", line, 0);
1809
- rb_define_method(cNokogiriXmlNode, "line=", set_line, 1);
1810
- rb_define_method(cNokogiriXmlNode, "content", get_native_content, 0);
1811
- rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
1812
- rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
1813
- rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
1814
2128
 
1815
- rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
1816
- rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
1817
2129
  rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
1818
- rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
1819
2130
  rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
1820
- 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);
1821
2133
  rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
1822
- rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
1823
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);
1824
2139
  rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
1825
2140
  rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
1826
- rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
1827
2141
 
1828
2142
  id_decorate = rb_intern("decorate");
1829
2143
  id_decorate_bang = rb_intern("decorate!");
1830
2144
  }
1831
-
1832
- /* vim: set noet sw=4 sws=4 */