nokogiri 1.8.5-java → 1.9.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 (160) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +0 -1
  3. data/ext/java/nokogiri/XmlAttr.java +3 -1
  4. data/ext/java/nokogiri/XmlDtd.java +20 -16
  5. data/ext/java/nokogiri/XmlElement.java +6 -6
  6. data/ext/java/nokogiri/XmlNode.java +29 -9
  7. data/ext/java/nokogiri/XmlNodeSet.java +258 -77
  8. data/ext/java/nokogiri/XmlXpathContext.java +10 -12
  9. data/ext/java/nokogiri/internals/NokogiriHelpers.java +25 -23
  10. data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +5 -5
  11. data/ext/java/nokogiri/internals/XalanDTMManagerPatch.java +11 -10
  12. data/ext/java/{org/apache/xml/dtm/ref/dom2dtm/DOM2DTMExt.java → nokogiri/internals/dom2dtm/DOM2DTM.java} +3 -7
  13. data/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java +685 -0
  14. data/ext/nokogiri/extconf.rb +10 -6
  15. data/ext/nokogiri/xml_attr.c +26 -21
  16. data/ext/nokogiri/xml_document.c +4 -1
  17. data/ext/nokogiri/xml_namespace.c +3 -3
  18. data/ext/nokogiri/xml_namespace.h +1 -2
  19. data/ext/nokogiri/xml_node.c +55 -15
  20. data/lib/nokogiri/css/parser.rb +61 -61
  21. data/lib/nokogiri/nokogiri.jar +0 -0
  22. data/lib/nokogiri/version.rb +1 -1
  23. data/lib/nokogiri/xml/document_fragment.rb +11 -0
  24. data/lib/nokogiri/xml/node.rb +12 -0
  25. data/lib/nokogiri/xml/node_set.rb +4 -8
  26. data/lib/xercesImpl.jar +0 -0
  27. metadata +17 -152
  28. data/.autotest +0 -22
  29. data/.cross_rubies +0 -8
  30. data/.editorconfig +0 -17
  31. data/.gemtest +0 -0
  32. data/.travis.yml +0 -63
  33. data/CHANGELOG.md +0 -1368
  34. data/CONTRIBUTING.md +0 -42
  35. data/C_CODING_STYLE.rdoc +0 -33
  36. data/Gemfile +0 -23
  37. data/Gemfile-libxml-ruby +0 -3
  38. data/Manifest.txt +0 -370
  39. data/ROADMAP.md +0 -111
  40. data/Rakefile +0 -348
  41. data/SECURITY.md +0 -19
  42. data/STANDARD_RESPONSES.md +0 -47
  43. data/Y_U_NO_GEMSPEC.md +0 -155
  44. data/appveyor.yml +0 -29
  45. data/build_all +0 -44
  46. data/patches/sort-patches-by-date +0 -25
  47. data/suppressions/README.txt +0 -1
  48. data/suppressions/nokogiri_ruby-2.supp +0 -10
  49. data/tasks/test.rb +0 -100
  50. data/test/css/test_nthiness.rb +0 -226
  51. data/test/css/test_parser.rb +0 -386
  52. data/test/css/test_tokenizer.rb +0 -215
  53. data/test/css/test_xpath_visitor.rb +0 -96
  54. data/test/decorators/test_slop.rb +0 -23
  55. data/test/files/2ch.html +0 -108
  56. data/test/files/GH_1042.html +0 -18
  57. data/test/files/address_book.rlx +0 -12
  58. data/test/files/address_book.xml +0 -10
  59. data/test/files/atom.xml +0 -344
  60. data/test/files/bar/bar.xsd +0 -4
  61. data/test/files/bogus.xml +0 -0
  62. data/test/files/dont_hurt_em_why.xml +0 -422
  63. data/test/files/encoding.html +0 -82
  64. data/test/files/encoding.xhtml +0 -84
  65. data/test/files/exslt.xml +0 -8
  66. data/test/files/exslt.xslt +0 -35
  67. data/test/files/foo/foo.xsd +0 -4
  68. data/test/files/metacharset.html +0 -10
  69. data/test/files/namespace_pressure_test.xml +0 -1684
  70. data/test/files/noencoding.html +0 -47
  71. data/test/files/po.xml +0 -32
  72. data/test/files/po.xsd +0 -66
  73. data/test/files/saml/saml20assertion_schema.xsd +0 -283
  74. data/test/files/saml/saml20protocol_schema.xsd +0 -302
  75. data/test/files/saml/xenc_schema.xsd +0 -146
  76. data/test/files/saml/xmldsig_schema.xsd +0 -318
  77. data/test/files/shift_jis.html +0 -10
  78. data/test/files/shift_jis.xml +0 -5
  79. data/test/files/shift_jis_no_charset.html +0 -9
  80. data/test/files/slow-xpath.xml +0 -25509
  81. data/test/files/snuggles.xml +0 -3
  82. data/test/files/staff.dtd +0 -10
  83. data/test/files/staff.xml +0 -59
  84. data/test/files/staff.xslt +0 -32
  85. data/test/files/test_document_url/bar.xml +0 -2
  86. data/test/files/test_document_url/document.dtd +0 -4
  87. data/test/files/test_document_url/document.xml +0 -6
  88. data/test/files/tlm.html +0 -851
  89. data/test/files/to_be_xincluded.xml +0 -2
  90. data/test/files/valid_bar.xml +0 -2
  91. data/test/files/xinclude.xml +0 -4
  92. data/test/helper.rb +0 -271
  93. data/test/html/sax/test_parser.rb +0 -168
  94. data/test/html/sax/test_parser_context.rb +0 -46
  95. data/test/html/sax/test_parser_text.rb +0 -163
  96. data/test/html/sax/test_push_parser.rb +0 -87
  97. data/test/html/test_attributes.rb +0 -85
  98. data/test/html/test_builder.rb +0 -164
  99. data/test/html/test_document.rb +0 -712
  100. data/test/html/test_document_encoding.rb +0 -143
  101. data/test/html/test_document_fragment.rb +0 -310
  102. data/test/html/test_element_description.rb +0 -105
  103. data/test/html/test_named_characters.rb +0 -14
  104. data/test/html/test_node.rb +0 -212
  105. data/test/html/test_node_encoding.rb +0 -91
  106. data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +0 -14
  107. data/test/namespaces/test_namespaces_aliased_default.rb +0 -24
  108. data/test/namespaces/test_namespaces_in_builder_doc.rb +0 -75
  109. data/test/namespaces/test_namespaces_in_cloned_doc.rb +0 -31
  110. data/test/namespaces/test_namespaces_in_created_doc.rb +0 -75
  111. data/test/namespaces/test_namespaces_in_parsed_doc.rb +0 -80
  112. data/test/namespaces/test_namespaces_preservation.rb +0 -31
  113. data/test/test_convert_xpath.rb +0 -135
  114. data/test/test_css_cache.rb +0 -47
  115. data/test/test_encoding_handler.rb +0 -48
  116. data/test/test_memory_leak.rb +0 -156
  117. data/test/test_nokogiri.rb +0 -138
  118. data/test/test_soap4r_sax.rb +0 -52
  119. data/test/test_xslt_transforms.rb +0 -314
  120. data/test/xml/node/test_save_options.rb +0 -28
  121. data/test/xml/node/test_subclass.rb +0 -44
  122. data/test/xml/sax/test_parser.rb +0 -402
  123. data/test/xml/sax/test_parser_context.rb +0 -115
  124. data/test/xml/sax/test_parser_text.rb +0 -202
  125. data/test/xml/sax/test_push_parser.rb +0 -265
  126. data/test/xml/test_attr.rb +0 -74
  127. data/test/xml/test_attribute_decl.rb +0 -86
  128. data/test/xml/test_builder.rb +0 -341
  129. data/test/xml/test_c14n.rb +0 -180
  130. data/test/xml/test_cdata.rb +0 -54
  131. data/test/xml/test_comment.rb +0 -40
  132. data/test/xml/test_document.rb +0 -982
  133. data/test/xml/test_document_encoding.rb +0 -31
  134. data/test/xml/test_document_fragment.rb +0 -298
  135. data/test/xml/test_dtd.rb +0 -187
  136. data/test/xml/test_dtd_encoding.rb +0 -31
  137. data/test/xml/test_element_content.rb +0 -56
  138. data/test/xml/test_element_decl.rb +0 -73
  139. data/test/xml/test_entity_decl.rb +0 -122
  140. data/test/xml/test_entity_reference.rb +0 -262
  141. data/test/xml/test_namespace.rb +0 -96
  142. data/test/xml/test_node.rb +0 -1325
  143. data/test/xml/test_node_attributes.rb +0 -115
  144. data/test/xml/test_node_encoding.rb +0 -75
  145. data/test/xml/test_node_inheritance.rb +0 -32
  146. data/test/xml/test_node_reparenting.rb +0 -592
  147. data/test/xml/test_node_set.rb +0 -809
  148. data/test/xml/test_parse_options.rb +0 -64
  149. data/test/xml/test_processing_instruction.rb +0 -30
  150. data/test/xml/test_reader.rb +0 -620
  151. data/test/xml/test_reader_encoding.rb +0 -134
  152. data/test/xml/test_relax_ng.rb +0 -60
  153. data/test/xml/test_schema.rb +0 -142
  154. data/test/xml/test_syntax_error.rb +0 -36
  155. data/test/xml/test_text.rb +0 -60
  156. data/test/xml/test_unparented_node.rb +0 -483
  157. data/test/xml/test_xinclude.rb +0 -83
  158. data/test/xml/test_xpath.rb +0 -470
  159. data/test/xslt/test_custom_functions.rb +0 -133
  160. data/test/xslt/test_exception_handling.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e9727f93d46220b9a004551304a4ec6cba2243ac
4
- data.tar.gz: 41168fc5b0521a0d28c06790cfc9c33b4ec0d37c
2
+ SHA256:
3
+ metadata.gz: 91e6ae003618927051f0376df1b2ebf3eece79ac535a15e874c95ec0850e3bd0
4
+ data.tar.gz: 2f1f1f47c821664706826c4eb46120ef08e8d7f88561ccc43fbf95df463865c7
5
5
  SHA512:
6
- metadata.gz: 737c5fa0fff34cb9f8976f57c0b5b5dfe465b288b420f60af77159ca95c4b7d7dce7c990f1ef692fc0eccf94bcfed468ea483a377ca5784858fbfa3893585f0b
7
- data.tar.gz: 88d8fbfe169eff929bc5fca87a5316c5d2a42f56bf07263e8a63e48a893ee4edd3c3292f144f36044ac53d321338dbd668912ded2077d962e0637d4c43936b01
6
+ metadata.gz: de19599baccd1ef2be9b9db9076996dd6c301e6467891ba06433a55adbc2aec03a377b100178acce4093e5b950533eba7e6298e55f11346edc817093b7fc4947
7
+ data.tar.gz: da62dac978f94e9cfab0515090cb1c34c27c1bee796efe4d8a010eacb91bcf30536e9edc49412b4d776e61a390801fcc4c5d5ea81b8e001fd2824718a8af5d9a
data/README.md CHANGED
@@ -18,7 +18,6 @@ or CSS3 selectors.
18
18
 
19
19
  [![Concourse CI](https://ci.nokogiri.org/api/v1/teams/nokogiri-core/pipelines/nokogiri/jobs/ruby-2.4-system/badge)](https://ci.nokogiri.org/teams/nokogiri-core/pipelines/nokogiri?groups=master)
20
20
  [![Code Climate](https://codeclimate.com/github/sparklemotion/nokogiri.svg)](https://codeclimate.com/github/sparklemotion/nokogiri)
21
- [![Version Eye](https://www.versioneye.com/ruby/nokogiri/badge.png)](https://www.versioneye.com/ruby/nokogiri)
22
21
  [![Join the chat at https://gitter.im/sparklemotion/nokogiri](https://badges.gitter.im/sparklemotion/nokogiri.svg)](https://gitter.im/sparklemotion/nokogiri?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
23
22
 
24
23
 
@@ -130,7 +130,9 @@ public class XmlAttr extends XmlNode {
130
130
  @JRubyMethod(name = {"value=", "content="})
131
131
  public IRubyObject value_set(ThreadContext context, IRubyObject content){
132
132
  Attr attr = (Attr) node;
133
- attr.setValue(rubyStringToString(XmlNode.encode_special_chars(context, content)));
133
+ if (content != null && !content.isNil()) {
134
+ attr.setValue(rubyStringToString(XmlNode.encode_special_chars(context, content)));
135
+ }
134
136
  setContent(content);
135
137
  return content;
136
138
  }
@@ -35,9 +35,11 @@ package nokogiri;
35
35
  import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
36
36
  import static nokogiri.internals.NokogiriHelpers.nonEmptyStringOrNil;
37
37
  import static nokogiri.internals.NokogiriHelpers.stringOrNil;
38
- import static org.jruby.javasupport.util.RuntimeHelpers.invoke;
39
- import nokogiri.internals.NokogiriHelpers;
40
- import nokogiri.internals.SaveContextVisitor;
38
+ import static org.jruby.runtime.Helpers.invoke;
39
+
40
+ import java.util.ArrayList;
41
+ import java.util.Arrays;
42
+ import java.util.List;
41
43
 
42
44
  import org.apache.xerces.xni.QName;
43
45
  import org.cyberneko.dtd.DTDConfiguration;
@@ -54,6 +56,9 @@ import org.w3c.dom.DocumentType;
54
56
  import org.w3c.dom.Element;
55
57
  import org.w3c.dom.Node;
56
58
 
59
+ import nokogiri.internals.NokogiriHelpers;
60
+ import nokogiri.internals.SaveContextVisitor;
61
+
57
62
  /**
58
63
  * Class for Nokogiri::XML::DTD
59
64
  *
@@ -64,8 +69,6 @@ import org.w3c.dom.Node;
64
69
 
65
70
  @JRubyClass(name="Nokogiri::XML::DTD", parent="Nokogiri::XML::Node")
66
71
  public class XmlDtd extends XmlNode {
67
- protected RubyArray allDecls = null;
68
-
69
72
  /** cache of children, Nokogiri::XML::NodeSet */
70
73
  protected IRubyObject children = null;
71
74
 
@@ -369,7 +372,6 @@ public class XmlDtd extends XmlNode {
369
372
  Ruby runtime = context.getRuntime();
370
373
 
371
374
  // initialize data structures
372
- allDecls = RubyArray.newArray(runtime);
373
375
  attributes = RubyHash.newHash(runtime);
374
376
  elements = RubyHash.newHash(runtime);
375
377
  entities = RubyHash.newHash(runtime);
@@ -379,10 +381,9 @@ public class XmlDtd extends XmlNode {
379
381
 
380
382
  // recursively extract decls
381
383
  if (node == null) return; // leave all the decl hash's empty
382
- extractDecls(context, node.getFirstChild());
383
384
 
384
385
  // convert allDecls to a NodeSet
385
- children = XmlNodeSet.newXmlNodeSet(context, allDecls);
386
+ children = XmlNodeSet.newXmlNodeSet(context, extractDecls(context, node.getFirstChild()));
386
387
 
387
388
  // add attribute decls as attributes to the matching element decl
388
389
  RubyArray keys = attributes.keys();
@@ -425,25 +426,26 @@ public class XmlDtd extends XmlNode {
425
426
  * subset it extracts everything and assumess <code>node</code>
426
427
  * and all children are part of the external subset.
427
428
  */
428
- protected void extractDecls(ThreadContext context, Node node) {
429
+ protected IRubyObject[] extractDecls(ThreadContext context, Node node) {
430
+ List<IRubyObject> decls = new ArrayList<IRubyObject>();
429
431
  while (node != null) {
430
432
  if (isExternalSubset(node)) {
431
- return;
433
+ break;
432
434
  } else if (isAttributeDecl(node)) {
433
435
  XmlAttributeDecl decl = (XmlAttributeDecl)
434
436
  XmlAttributeDecl.create(context, node);
435
437
  attributes.op_aset(context, decl.attribute_name(context), decl);
436
- allDecls.append(decl);
438
+ decls.add(decl);
437
439
  } else if (isElementDecl(node)) {
438
440
  XmlElementDecl decl = (XmlElementDecl)
439
441
  XmlElementDecl.create(context, node);
440
442
  elements.op_aset(context, decl.element_name(context), decl);
441
- allDecls.append(decl);
443
+ decls.add(decl);
442
444
  } else if (isEntityDecl(node)) {
443
445
  XmlEntityDecl decl = (XmlEntityDecl)
444
446
  XmlEntityDecl.create(context, node);
445
447
  entities.op_aset(context, decl.node_name(context), decl);
446
- allDecls.append(decl);
448
+ decls.add(decl);
447
449
  } else if (isNotationDecl(node)) {
448
450
  XmlNode tmp = (XmlNode)
449
451
  NokogiriHelpers.constructNode(context.getRuntime(), node);
@@ -453,7 +455,7 @@ public class XmlDtd extends XmlNode {
453
455
  tmp.getAttribute(context, "sysid"));
454
456
  notations.op_aset(context,
455
457
  tmp.getAttribute(context, "name"), decl);
456
- allDecls.append(decl);
458
+ decls.add(decl);
457
459
  } else if (isContentModel(node)) {
458
460
  XmlElementContent cm =
459
461
  new XmlElementContent(context.getRuntime(),
@@ -462,13 +464,15 @@ public class XmlDtd extends XmlNode {
462
464
  contentModels.op_aset(context, cm.element_name(context), cm);
463
465
  } else {
464
466
  // recurse
465
- extractDecls(context, node.getFirstChild());
467
+ decls.addAll(Arrays.asList(extractDecls(context, node.getFirstChild())));
466
468
  }
467
469
 
468
470
  node = node.getNextSibling();
469
471
  }
472
+
473
+ return decls.toArray(new IRubyObject[decls.size()]);
470
474
  }
471
-
475
+
472
476
  @Override
473
477
  public void accept(ThreadContext context, SaveContextVisitor visitor) {
474
478
  // since we use nekoDTD to parse dtd, node might be ElementImpl type
@@ -32,16 +32,16 @@
32
32
 
33
33
  package nokogiri;
34
34
 
35
- import nokogiri.internals.SaveContextVisitor;
36
-
37
35
  import org.jruby.Ruby;
38
- import org.jruby.RubyArray;
39
36
  import org.jruby.RubyClass;
40
37
  import org.jruby.anno.JRubyClass;
41
38
  import org.jruby.runtime.ThreadContext;
39
+ import org.jruby.runtime.builtin.IRubyObject;
42
40
  import org.w3c.dom.Element;
43
41
  import org.w3c.dom.Node;
44
42
 
43
+ import nokogiri.internals.SaveContextVisitor;
44
+
45
45
  /**
46
46
  * Class for Nokogiri::XML::Element
47
47
  *
@@ -71,9 +71,9 @@ public class XmlElement extends XmlNode {
71
71
  visitor.enter((Element) node);
72
72
  XmlNodeSet xmlNodeSet = (XmlNodeSet) children(context);
73
73
  if (xmlNodeSet.length() > 0) {
74
- RubyArray nodes = xmlNodeSet.nodes;
75
- for( int i = 0; i < nodes.size(); i++ ) {
76
- Object item = nodes.eltInternal(i);
74
+ IRubyObject[] nodes = XmlNodeSet.getNodes(context, xmlNodeSet);
75
+ for( int i = 0; i < nodes.length; i++ ) {
76
+ Object item = nodes[i];
77
77
  if (item instanceof XmlNode) {
78
78
  ((XmlNode) item).accept(context, visitor);
79
79
  }
@@ -472,10 +472,31 @@ public class XmlNode extends RubyObject {
472
472
  String nsURI = e.lookupNamespaceURI(prefix);
473
473
  this.node = NokogiriHelpers.renameNode(e, nsURI, e.getNodeName());
474
474
 
475
- if (nsURI == null || nsURI.isEmpty()) {
475
+ if (nsURI == null || nsURI == "") {
476
476
  return;
477
477
  }
478
478
 
479
+ String currentPrefix = e.getParentNode().lookupPrefix(nsURI);
480
+ String currentURI = e.getParentNode().lookupNamespaceURI(prefix);
481
+ boolean isDefault = e.getParentNode().isDefaultNamespace(nsURI);
482
+
483
+ // add xmlns attribute if this is a new root node or if the node's
484
+ // namespace isn't a default namespace in the new document
485
+ if (e.getParentNode().getNodeType() == Node.DOCUMENT_NODE) {
486
+ // this is the root node, so we must set the namespaces attributes
487
+ // anyway
488
+ e.setAttribute(prefix == null ? "xmlns":"xmlns:"+prefix, nsURI);
489
+ } else if (prefix == null) {
490
+ if (!isDefault)
491
+ // this is a default namespace but isn't the default where this
492
+ // node is being added
493
+ e.setAttribute("xmlns", nsURI);
494
+ } else if (currentPrefix != prefix || currentURI != nsURI) {
495
+ // this is a prefixed namespace but doens't have the same prefix or
496
+ // the prefix is set to a diffent URI
497
+ e.setAttribute("xmlns:"+prefix, nsURI);
498
+ }
499
+
479
500
  if (e.hasAttributes()) {
480
501
  NamedNodeMap attrs = e.getAttributes();
481
502
 
@@ -704,7 +725,7 @@ public class XmlNode extends RubyObject {
704
725
 
705
726
  @JRubyMethod
706
727
  public IRubyObject children(ThreadContext context) {
707
- XmlNodeSet xmlNodeSet = XmlNodeSet.create(context.runtime);
728
+ XmlNodeSet xmlNodeSet = XmlNodeSet.newEmptyNodeSet(context);
708
729
 
709
730
  NodeList nodeList = node.getChildNodes();
710
731
  if (nodeList.getLength() > 0) {
@@ -737,8 +758,8 @@ public class XmlNode extends RubyObject {
737
758
  public IRubyObject element_children(ThreadContext context) {
738
759
  List<Node> elementNodes = new ArrayList<Node>();
739
760
  addElements(node, elementNodes, false);
740
- if (elementNodes.size() == 0) return XmlNodeSet.newEmptyNodeSet(context);
741
- RubyArray array = NokogiriHelpers.nodeArrayToRubyArray(context.getRuntime(), elementNodes.toArray(new Node[0]));
761
+ IRubyObject[] array = NokogiriHelpers.nodeArrayToArray(context.runtime,
762
+ elementNodes.toArray(new Node[0]));
742
763
  XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, array);
743
764
  return xmlNodeSet;
744
765
  }
@@ -839,10 +860,10 @@ public class XmlNode extends RubyObject {
839
860
  RubyArray docErrors = getErrorArray(doc);
840
861
  if (isErrorIncreased(documentErrors, docErrors)) {
841
862
  for (int i = 0; i < docErrors.getLength(); i++) {
842
- documentErrors.add(docErrors.get(i));
863
+ documentErrors.add(docErrors.entry(i));
843
864
  }
844
865
  document.setInstanceVariable("@errors", documentErrors);
845
- XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, RubyArray.newArray(runtime));
866
+ XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, new IRubyObject[0]);
846
867
  return xmlNodeSet;
847
868
  }
848
869
 
@@ -854,10 +875,9 @@ public class XmlNode extends RubyObject {
854
875
  } else {
855
876
  first = doc.node.getFirstChild();
856
877
  }
857
- RubyArray nodeArray = RubyArray.newArray(runtime);
858
- nodeArray.add(NokogiriHelpers.getCachedNodeOrCreate(runtime, first));
859
878
 
860
- XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, nodeArray);
879
+ IRubyObject[] nodes = new IRubyObject[]{NokogiriHelpers.getCachedNodeOrCreate(runtime, first)};
880
+ XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, nodes);
861
881
  return xmlNodeSet;
862
882
  }
863
883
 
@@ -17,10 +17,10 @@
17
17
  * distribute, sublicense, and/or sell copies of the Software, and to
18
18
  * permit persons to whom the Software is furnished to do so, subject to
19
19
  * the following conditions:
20
- *
20
+ *
21
21
  * The above copyright notice and this permission notice shall be
22
22
  * included in all copies or substantial portions of the Software.
23
- *
23
+ *
24
24
  * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
25
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
26
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -36,12 +36,13 @@ import static nokogiri.XmlNode.setDocumentAndDecorate;
36
36
  import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
37
37
  import static nokogiri.internals.NokogiriHelpers.nodeListToRubyArray;
38
38
 
39
- import java.util.List;
39
+ import java.util.Arrays;
40
40
 
41
41
  import org.jruby.Ruby;
42
- import org.jruby.RubyArray;
43
42
  import org.jruby.RubyClass;
43
+ import org.jruby.RubyFixnum;
44
44
  import org.jruby.RubyObject;
45
+ import org.jruby.RubyRange;
45
46
  import org.jruby.anno.JRubyClass;
46
47
  import org.jruby.anno.JRubyMethod;
47
48
  import org.jruby.runtime.Block;
@@ -59,30 +60,38 @@ import org.w3c.dom.NodeList;
59
60
  @JRubyClass(name="Nokogiri::XML::NodeSet")
60
61
  public class XmlNodeSet extends RubyObject implements NodeList {
61
62
 
62
- RubyArray nodes;
63
-
63
+ private IRubyObject[] nodes;
64
+
65
+ @JRubyMethod(name = "new", meta = true, rest = true)
66
+ public static IRubyObject rbNew(ThreadContext context, IRubyObject cls,
67
+ IRubyObject[] args, Block block) {
68
+ RubyClass klass = (RubyClass) cls;
69
+ XmlNodeSet set = (XmlNodeSet) klass.allocate();
70
+ set.setNodes(new IRubyObject[0]);
71
+ set.callInit(args, block);
72
+ return set;
73
+ }
74
+
64
75
  public XmlNodeSet(Ruby ruby, RubyClass klazz) {
65
76
  super(ruby, klazz);
66
77
  }
67
78
 
68
- public static XmlNodeSet create(final Ruby runtime) {
79
+ private static XmlNodeSet create(final Ruby runtime) {
69
80
  return (XmlNodeSet) NokogiriService.XML_NODESET_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, "Nokogiri::XML::NodeSet"));
70
81
  }
71
82
 
72
83
  public static XmlNodeSet newEmptyNodeSet(ThreadContext context) {
73
- return create(context.getRuntime());
84
+ XmlNodeSet set = create(context.getRuntime());
85
+ set.nodes = new IRubyObject[0];
86
+ return set;
74
87
  }
75
88
 
76
- public static XmlNodeSet newXmlNodeSet(final Ruby runtime, RubyArray nodes) {
77
- XmlNodeSet xmlNodeSet = create(runtime);
89
+ public static XmlNodeSet newXmlNodeSet(ThreadContext context, IRubyObject[] nodes) {
90
+ XmlNodeSet xmlNodeSet = create(context.runtime);
78
91
  xmlNodeSet.setNodes(nodes);
79
92
  return xmlNodeSet;
80
93
  }
81
94
 
82
- static XmlNodeSet newXmlNodeSet(ThreadContext context, RubyArray nodes) {
83
- return newXmlNodeSet(context.getRuntime(), nodes);
84
- }
85
-
86
95
  /**
87
96
  * Create and return a copy of this object.
88
97
  *
@@ -93,19 +102,18 @@ public class XmlNodeSet extends RubyObject implements NodeList {
93
102
  return super.clone();
94
103
  }
95
104
 
96
- void setNodes(RubyArray array) {
105
+ void setNodes(IRubyObject[] array) {
97
106
  this.nodes = array;
98
107
 
99
- IRubyObject first = array.first();
100
- initialize(array.getRuntime(), first);
108
+ IRubyObject first = array.length > 0 ? array[0] : null;
109
+ initialize(getRuntime(), first);
101
110
  }
102
111
 
103
112
  private void setReference(XmlNodeSet reference) {
104
- this.nodes = null;
105
- IRubyObject first = reference.nodes.first();
106
- initialize(reference.getRuntime(), first);
113
+ IRubyObject first = reference.nodes.length > 0 ? reference.nodes[0] : null;
114
+ initialize(getRuntime(), first);
107
115
  }
108
-
116
+
109
117
  public void setNodeList(NodeList nodeList) {
110
118
  setNodes(nodeListToRubyArray(getRuntime(), nodeList));
111
119
  }
@@ -118,106 +126,280 @@ public class XmlNodeSet extends RubyObject implements NodeList {
118
126
  }
119
127
 
120
128
  public int length() {
121
- if (nodes == null) return 0;
122
- return nodes.size();
129
+ return nodes == null ? 0 : nodes.length;
123
130
  }
124
131
 
125
132
  public void relink_namespace(ThreadContext context) {
126
- List<?> n = nodes.getList();
127
-
128
- for (int i = 0; i < n.size(); i++) {
129
- if (n.get(i) instanceof XmlNode) {
130
- ((XmlNode) n.get(i)).relink_namespace(context);
133
+ for (int i = 0; i < nodes.length; i++) {
134
+ if (nodes[i] instanceof XmlNode) {
135
+ ((XmlNode) nodes[i]).relink_namespace(context);
131
136
  }
132
137
  }
133
138
  }
134
139
 
135
140
  @JRubyMethod(name="&")
136
- public IRubyObject and(ThreadContext context, IRubyObject nodeSet) {
137
- if (nodes == null) setNodes(RubyArray.newEmptyArray(context.getRuntime()));
138
- return newXmlNodeSet(context, (RubyArray) nodes.op_and(getNodes(context, nodeSet)));
141
+ public IRubyObject op_and(ThreadContext context, IRubyObject nodeSet) {
142
+ IRubyObject[] otherNodes = getNodes(context, nodeSet);
143
+
144
+ if (otherNodes == null || otherNodes.length == 0) {
145
+ return newEmptyNodeSet(context);
146
+ }
147
+
148
+ if (nodes == null || nodes.length == 0) {
149
+ return newEmptyNodeSet(context);
150
+ }
151
+
152
+ IRubyObject[] curr = nodes;
153
+ IRubyObject[] other = getNodes(context, nodeSet);
154
+ IRubyObject[] result = new IRubyObject[nodes.length];
155
+
156
+ int last = 0;
157
+ outer:
158
+ for (int i = 0; i < curr.length; i++) {
159
+ IRubyObject n = curr[i];
160
+
161
+ for (int j = 0; j < other.length; j++) {
162
+ if (other[j] == n) {
163
+ result[last++] = n;
164
+ continue outer;
165
+ }
166
+ }
167
+ }
168
+
169
+ XmlNodeSet newSet = newXmlNodeSet(context, Arrays.copyOf(result, last));
170
+ newSet.setReference(this);
171
+ return newSet;
139
172
  }
140
173
 
141
174
  @JRubyMethod
142
175
  public IRubyObject delete(ThreadContext context, IRubyObject node_or_namespace) {
143
- if (nodes == null) return context.getRuntime().getNil();
144
- if (node_or_namespace instanceof XmlNamespace) {
145
- ((XmlNamespace) node_or_namespace).deleteHref();
176
+ IRubyObject nodeOrNamespace = asXmlNodeOrNamespace(context, node_or_namespace);
177
+
178
+ if (nodes.length == 0) {
179
+ return context.nil;
180
+ }
181
+
182
+ IRubyObject[] orig = nodes;
183
+ IRubyObject[] result = new IRubyObject[nodes.length];
184
+
185
+ int last = 0;
186
+
187
+ for (int i = 0; i < orig.length; i++) {
188
+ IRubyObject n = orig[i];
189
+
190
+ if (n == nodeOrNamespace) {
191
+ continue;
192
+ }
193
+
194
+ result[last++] = n;
146
195
  }
147
- return nodes.delete(context, asXmlNodeOrNamespace(context, node_or_namespace), Block.NULL_BLOCK);
196
+
197
+ if (nodeOrNamespace instanceof XmlNamespace) {
198
+ ((XmlNamespace) nodeOrNamespace).deleteHref();
199
+ }
200
+
201
+ nodes = Arrays.copyOf(result, last);
202
+
203
+ if (nodes.length < orig.length) {
204
+ // if we found the node return it
205
+ return nodeOrNamespace;
206
+ }
207
+
208
+ return context.nil;
148
209
  }
149
210
 
150
211
  @JRubyMethod
151
- public IRubyObject dup(ThreadContext context){
152
- if (nodes == null) return newEmptyNodeSet(context);
153
- return newXmlNodeSet(context, nodes.aryDup());
212
+ public IRubyObject dup(ThreadContext context) {
213
+ return newXmlNodeSet(context, nodes);
154
214
  }
155
215
 
156
216
  @JRubyMethod(name = "include?")
157
217
  public IRubyObject include_p(ThreadContext context, IRubyObject node_or_namespace) {
158
- node_or_namespace = asXmlNodeOrNamespace(context, node_or_namespace);
159
- if (nodes == null) return context.getRuntime().getFalse();
160
- return nodes.include_p(context, node_or_namespace);
218
+ for (int i = 0; i < nodes.length; i++) {
219
+ if (nodes[i] == node_or_namespace) {
220
+ return context.tru;
221
+ }
222
+ }
223
+
224
+ return context.runtime.getFalse();
161
225
  }
162
226
 
163
227
  @JRubyMethod(name = {"length", "size"})
164
228
  public IRubyObject length(ThreadContext context) {
165
- return nodes != null ? nodes.length() : context.getRuntime().newFixnum(0);
229
+ return context.getRuntime().newFixnum(nodes.length);
166
230
  }
167
231
 
168
232
  @JRubyMethod(name="-")
169
233
  public IRubyObject op_diff(ThreadContext context, IRubyObject nodeSet) {
170
- XmlNodeSet xmlNodeSet = newXmlNodeSet(context, this);
171
- if (nodes == null) setNodes(RubyArray.newEmptyArray(context.getRuntime()));
172
- xmlNodeSet.setNodes((RubyArray) nodes.op_diff(getNodes(context, nodeSet)));
173
- return xmlNodeSet;
234
+ IRubyObject[] otherNodes = getNodes(context, nodeSet);
235
+
236
+ if (otherNodes.length == 0) {
237
+ return dup(context);
238
+ }
239
+
240
+ if (nodes.length == 0) {
241
+ return newEmptyNodeSet(context);
242
+ }
243
+
244
+ IRubyObject[] curr = nodes;
245
+ IRubyObject[] other = getNodes(context, nodeSet);
246
+ IRubyObject[] result = new IRubyObject[nodes.length];
247
+
248
+ int last = 0;
249
+ outer:
250
+ for (int i = 0; i < curr.length; i++) {
251
+ IRubyObject n = curr[i];
252
+
253
+ for (int j = 0; j < other.length; j++) {
254
+ if (other[j] == n) {
255
+ continue outer;
256
+ }
257
+ }
258
+
259
+ result[last++] = n;
260
+ }
261
+
262
+ XmlNodeSet newSet = newXmlNodeSet(context, Arrays.copyOf(result, last));
263
+ newSet.setReference(this);
264
+ return newSet;
174
265
  }
175
266
 
176
267
  @JRubyMethod(name={"|", "+"})
177
268
  public IRubyObject op_or(ThreadContext context, IRubyObject nodeSet) {
178
- if (nodes == null) setNodes(RubyArray.newEmptyArray(context.getRuntime()));
179
- return newXmlNodeSet(context, (RubyArray) nodes.op_or(getNodes(context, nodeSet)));
269
+ IRubyObject[] otherNodes = getNodes(context, nodeSet);
270
+
271
+ if (nodes.length == 0) {
272
+ return ((XmlNodeSet) nodeSet).dup(context);
273
+ }
274
+
275
+ if (otherNodes.length == 0) {
276
+ return dup(context);
277
+ }
278
+
279
+ IRubyObject[] curr = nodes;
280
+ IRubyObject[] other = getNodes(context, nodeSet);
281
+ IRubyObject[] result = Arrays.copyOf(curr, curr.length + other.length);
282
+
283
+ int last = curr.length;
284
+ outer:
285
+ for (int i = 0; i < other.length; i++) {
286
+ IRubyObject n = other[i];
287
+
288
+ for (int j = 0; j < curr.length; j++) {
289
+ if (curr[j] == n) {
290
+ continue outer;
291
+ }
292
+ }
293
+
294
+ result[last++] = n;
295
+ }
296
+
297
+ XmlNodeSet newSet = newXmlNodeSet(context, Arrays.copyOf(result, last));
298
+ newSet.setReference(this);
299
+ return newSet;
180
300
  }
181
301
 
182
302
  @JRubyMethod(name = {"push", "<<"})
183
303
  public IRubyObject push(ThreadContext context, IRubyObject node_or_namespace) {
184
- if (nodes == null) setNodes(RubyArray.newArray(context.getRuntime()));
185
- nodes.append(asXmlNodeOrNamespace(context, node_or_namespace));
304
+ nodes = Arrays.copyOf(nodes, nodes.length+1);
305
+ nodes[nodes.length-1] = node_or_namespace;
186
306
  return this;
187
307
  }
188
308
 
309
+ // replace with
310
+ // https://github.com/jruby/jruby/blame/13a3ec76d883a162b9d46c374c6e9eeea27b3261/core/src/main/java/org/jruby/RubyRange.java#L974
311
+ // once we upgraded the min JRuby version to >= 9.2
312
+ private static IRubyObject rangeBeginLength(ThreadContext context, IRubyObject rangeMaybe, int len, int[] begLen) {
313
+ RubyRange range = (RubyRange) rangeMaybe;
314
+ int min = range.begin(context).convertToInteger().getIntValue();
315
+ int max = range.end(context).convertToInteger().getIntValue();
316
+
317
+ if (min < 0) {
318
+ min += len;
319
+ if (min < 0) {
320
+ throw context.runtime.newRangeError(min + ".." + (range.isExcludeEnd() ? "." : "") + max + " out of range");
321
+ }
322
+ }
323
+
324
+ if (max < 0) {
325
+ max += len;
326
+ }
327
+
328
+ if (!range.isExcludeEnd()) {
329
+ max++;
330
+ }
331
+
332
+ begLen[0] = min;
333
+ begLen[1] = max;
334
+ return context.tru;
335
+ }
336
+
337
+
189
338
  @JRubyMethod(name={"[]", "slice"})
190
- public IRubyObject slice(ThreadContext context, IRubyObject indexOrRange){
191
- if (nodes == null) return context.getRuntime().getNil();
192
- IRubyObject result = nodes.aref19(indexOrRange);
193
- if (result instanceof RubyArray) {
194
- return newXmlNodeSet(context, (RubyArray) result);
339
+ public IRubyObject slice(ThreadContext context, IRubyObject indexOrRange) {
340
+ if (indexOrRange instanceof RubyFixnum) {
341
+ int idx = ((RubyFixnum)indexOrRange).getIntValue();
342
+
343
+ if (idx < 0) {
344
+ idx += nodes.length;
345
+ }
346
+
347
+ if (idx >= nodes.length || idx < 0) {
348
+ return context.nil;
349
+ }
350
+
351
+ return nodes[idx];
195
352
  }
196
- return result;
353
+
354
+ int[] begLen = new int[2];
355
+ rangeBeginLength(context, indexOrRange, nodes.length, begLen);
356
+ int min = begLen[0];
357
+ int max = begLen[1];
358
+ return subseq(context, min, max - min);
197
359
  }
198
360
 
199
361
  @JRubyMethod(name={"[]", "slice"})
200
- public IRubyObject slice(ThreadContext context, IRubyObject start, IRubyObject length){
201
- if (nodes == null) return context.getRuntime().getNil();
202
- IRubyObject result = nodes.aref19(start, length);
203
- if (result instanceof RubyArray) {
204
- return newXmlNodeSet(context, (RubyArray) result);
362
+ public IRubyObject slice(ThreadContext context, IRubyObject start, IRubyObject length) {
363
+ int s = ((RubyFixnum) start).getIntValue();
364
+ int l = ((RubyFixnum) length).getIntValue();
365
+
366
+ if (s < 0) {
367
+ s += nodes.length;
205
368
  }
206
- return context.getRuntime().getNil();
369
+
370
+ return subseq(context, s, l);
371
+ }
372
+
373
+ public IRubyObject subseq(ThreadContext context, int start, int length) {
374
+ if (start > nodes.length) {
375
+ return context.nil;
376
+ }
377
+
378
+ if (start < 0 || length < 0) {
379
+ return context.nil;
380
+ }
381
+
382
+ if (start + length > nodes.length) {
383
+ length = nodes.length - start;
384
+ }
385
+
386
+ int to = start + length;
387
+
388
+ IRubyObject[] newNodes = Arrays.copyOfRange(nodes, start, to);
389
+
390
+ return newXmlNodeSet(context, newNodes);
207
391
  }
208
392
 
209
393
  @JRubyMethod(name = {"to_a", "to_ary"})
210
394
  public IRubyObject to_a(ThreadContext context) {
211
- return nodes;
395
+ return context.runtime.newArrayNoCopy(nodes);
212
396
  }
213
397
 
214
398
  @JRubyMethod(name = {"unlink", "remove"})
215
- public IRubyObject unlink(ThreadContext context){
216
- if (nodes == null) return this;
217
- IRubyObject[] arr = nodes.toJavaArrayUnsafe();
218
- for (int i = 0; i < arr.length; i++) {
219
- if (arr[i] instanceof XmlNode) {
220
- ((XmlNode) arr[i] ).unlink(context);
399
+ public IRubyObject unlink(ThreadContext context) {
400
+ for (int i = 0; i < nodes.length; i++) {
401
+ if (nodes[i] instanceof XmlNode) {
402
+ ((XmlNode) nodes[i] ).unlink(context);
221
403
  }
222
404
  }
223
405
  return this;
@@ -226,6 +408,7 @@ public class XmlNodeSet extends RubyObject implements NodeList {
226
408
  private static XmlNodeSet newXmlNodeSet(ThreadContext context, XmlNodeSet reference) {
227
409
  XmlNodeSet xmlNodeSet = create(context.getRuntime());
228
410
  xmlNodeSet.setReference(reference);
411
+ xmlNodeSet.nodes = new IRubyObject[0];
229
412
  return xmlNodeSet;
230
413
  }
231
414
 
@@ -236,21 +419,19 @@ public class XmlNodeSet extends RubyObject implements NodeList {
236
419
  throw context.getRuntime().newArgumentError("node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
237
420
  }
238
421
 
239
- private static RubyArray getNodes(ThreadContext context, IRubyObject possibleNodeSet) {
422
+ static IRubyObject[] getNodes(ThreadContext context, IRubyObject possibleNodeSet) {
240
423
  if (possibleNodeSet instanceof XmlNodeSet) {
241
- RubyArray nodes = ((XmlNodeSet) possibleNodeSet).nodes;
242
- return nodes == null ? RubyArray.newEmptyArray(context.getRuntime()) : nodes;
424
+ return ((XmlNodeSet) possibleNodeSet).nodes;
243
425
  }
244
426
  throw context.getRuntime().newArgumentError("node must be a Nokogiri::XML::NodeSet");
245
427
  }
246
-
428
+
247
429
  public int getLength() {
248
- return nodes == null ? 0 : nodes.size();
430
+ return nodes.length;
249
431
  }
250
-
432
+
251
433
  public Node item(int index) {
252
- if (nodes == null) return null;
253
- Object n = nodes.get(index);
434
+ Object n = nodes[index];
254
435
  if (n instanceof XmlNode) return ((XmlNode)n).node;
255
436
  if (n instanceof XmlNamespace) return ((XmlNamespace)n).getNode();
256
437
  return null;