nokogiri 1.10.10-java → 1.11.0.rc1-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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -17
  3. data/ext/java/nokogiri/HtmlDocument.java +34 -46
  4. data/ext/java/nokogiri/HtmlSaxParserContext.java +87 -57
  5. data/ext/java/nokogiri/NokogiriService.java +1 -1
  6. data/ext/java/nokogiri/XmlAttr.java +13 -20
  7. data/ext/java/nokogiri/XmlAttributeDecl.java +11 -12
  8. data/ext/java/nokogiri/XmlCdata.java +3 -4
  9. data/ext/java/nokogiri/XmlComment.java +1 -1
  10. data/ext/java/nokogiri/XmlDocument.java +148 -175
  11. data/ext/java/nokogiri/XmlDocumentFragment.java +13 -31
  12. data/ext/java/nokogiri/XmlDtd.java +5 -8
  13. data/ext/java/nokogiri/XmlElement.java +1 -20
  14. data/ext/java/nokogiri/XmlElementDecl.java +23 -28
  15. data/ext/java/nokogiri/XmlEntityDecl.java +23 -27
  16. data/ext/java/nokogiri/XmlEntityReference.java +2 -2
  17. data/ext/java/nokogiri/XmlNamespace.java +72 -89
  18. data/ext/java/nokogiri/XmlNode.java +300 -401
  19. data/ext/java/nokogiri/XmlNodeSet.java +70 -76
  20. data/ext/java/nokogiri/XmlReader.java +10 -11
  21. data/ext/java/nokogiri/XmlSaxParserContext.java +7 -7
  22. data/ext/java/nokogiri/XmlSchema.java +3 -3
  23. data/ext/java/nokogiri/XmlText.java +12 -9
  24. data/ext/java/nokogiri/XmlXpathContext.java +7 -7
  25. data/ext/java/nokogiri/XsltStylesheet.java +7 -15
  26. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +4 -10
  27. data/ext/java/nokogiri/internals/NokogiriHelpers.java +71 -135
  28. data/ext/java/nokogiri/internals/NokogiriNamespaceCache.java +90 -58
  29. data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +5 -4
  30. data/ext/java/nokogiri/internals/ParserContext.java +27 -73
  31. data/ext/java/nokogiri/internals/ReaderNode.java +2 -4
  32. data/ext/java/nokogiri/internals/XmlDomParserContext.java +17 -32
  33. data/ext/nokogiri/extconf.rb +44 -35
  34. data/ext/nokogiri/nokogiri.c +12 -6
  35. data/ext/nokogiri/nokogiri.h +1 -0
  36. data/ext/nokogiri/xml_document.c +10 -1
  37. data/ext/nokogiri/xml_node.c +20 -0
  38. data/ext/nokogiri/xml_schema.c +0 -29
  39. data/ext/nokogiri/xslt_stylesheet.c +0 -4
  40. data/lib/nokogiri.rb +2 -19
  41. data/lib/nokogiri/css.rb +1 -0
  42. data/lib/nokogiri/css/node.rb +1 -0
  43. data/lib/nokogiri/css/parser.rb +1 -0
  44. data/lib/nokogiri/css/parser_extras.rb +1 -0
  45. data/lib/nokogiri/css/syntax_error.rb +1 -0
  46. data/lib/nokogiri/css/tokenizer.rb +1 -0
  47. data/lib/nokogiri/css/xpath_visitor.rb +3 -1
  48. data/lib/nokogiri/decorators/slop.rb +1 -0
  49. data/lib/nokogiri/html.rb +1 -0
  50. data/lib/nokogiri/html/builder.rb +1 -0
  51. data/lib/nokogiri/html/document.rb +1 -0
  52. data/lib/nokogiri/html/document_fragment.rb +1 -0
  53. data/lib/nokogiri/html/element_description.rb +1 -0
  54. data/lib/nokogiri/html/element_description_defaults.rb +1 -0
  55. data/lib/nokogiri/html/entity_lookup.rb +1 -0
  56. data/lib/nokogiri/html/sax/parser.rb +1 -0
  57. data/lib/nokogiri/html/sax/parser_context.rb +1 -0
  58. data/lib/nokogiri/html/sax/push_parser.rb +1 -0
  59. data/lib/nokogiri/jruby/dependencies.rb +20 -0
  60. data/lib/nokogiri/nokogiri.jar +0 -0
  61. data/lib/nokogiri/syntax_error.rb +1 -0
  62. data/lib/nokogiri/version.rb +85 -45
  63. data/lib/nokogiri/xml.rb +1 -0
  64. data/lib/nokogiri/xml/attr.rb +1 -0
  65. data/lib/nokogiri/xml/attribute_decl.rb +1 -0
  66. data/lib/nokogiri/xml/builder.rb +1 -0
  67. data/lib/nokogiri/xml/cdata.rb +1 -0
  68. data/lib/nokogiri/xml/character_data.rb +1 -0
  69. data/lib/nokogiri/xml/document.rb +3 -8
  70. data/lib/nokogiri/xml/document_fragment.rb +1 -0
  71. data/lib/nokogiri/xml/dtd.rb +1 -0
  72. data/lib/nokogiri/xml/element_content.rb +1 -0
  73. data/lib/nokogiri/xml/element_decl.rb +1 -0
  74. data/lib/nokogiri/xml/entity_decl.rb +1 -0
  75. data/lib/nokogiri/xml/entity_reference.rb +1 -0
  76. data/lib/nokogiri/xml/namespace.rb +1 -0
  77. data/lib/nokogiri/xml/node.rb +26 -12
  78. data/lib/nokogiri/xml/node/save_options.rb +1 -0
  79. data/lib/nokogiri/xml/node_set.rb +1 -0
  80. data/lib/nokogiri/xml/notation.rb +1 -0
  81. data/lib/nokogiri/xml/parse_options.rb +4 -3
  82. data/lib/nokogiri/xml/pp.rb +1 -0
  83. data/lib/nokogiri/xml/pp/character_data.rb +1 -0
  84. data/lib/nokogiri/xml/pp/node.rb +1 -0
  85. data/lib/nokogiri/xml/processing_instruction.rb +1 -0
  86. data/lib/nokogiri/xml/reader.rb +7 -3
  87. data/lib/nokogiri/xml/relax_ng.rb +1 -0
  88. data/lib/nokogiri/xml/sax.rb +1 -0
  89. data/lib/nokogiri/xml/sax/document.rb +1 -0
  90. data/lib/nokogiri/xml/sax/parser.rb +1 -0
  91. data/lib/nokogiri/xml/sax/parser_context.rb +1 -0
  92. data/lib/nokogiri/xml/sax/push_parser.rb +1 -0
  93. data/lib/nokogiri/xml/schema.rb +1 -0
  94. data/lib/nokogiri/xml/searchable.rb +1 -0
  95. data/lib/nokogiri/xml/syntax_error.rb +1 -0
  96. data/lib/nokogiri/xml/text.rb +1 -0
  97. data/lib/nokogiri/xml/xpath.rb +1 -0
  98. data/lib/nokogiri/xml/xpath/syntax_error.rb +1 -0
  99. data/lib/nokogiri/xml/xpath_context.rb +1 -0
  100. data/lib/nokogiri/xslt.rb +1 -0
  101. data/lib/nokogiri/xslt/stylesheet.rb +1 -0
  102. data/lib/xsd/xmlparser/nokogiri.rb +1 -0
  103. metadata +26 -27
  104. data/ext/java/nokogiri/internals/NokogiriEncodingReaderWrapper.java +0 -107
  105. data/ext/java/nokogiri/internals/UncloseableInputStream.java +0 -102
@@ -33,24 +33,13 @@
33
33
  package nokogiri;
34
34
 
35
35
  import static java.lang.Math.max;
36
- import static nokogiri.internals.NokogiriHelpers.clearXpathContext;
37
- import static nokogiri.internals.NokogiriHelpers.convertEncoding;
38
- import static nokogiri.internals.NokogiriHelpers.convertString;
39
- import static nokogiri.internals.NokogiriHelpers.getCachedNodeOrCreate;
40
- import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
41
- import static nokogiri.internals.NokogiriHelpers.isBlank;
42
- import static nokogiri.internals.NokogiriHelpers.nodeArrayToRubyArray;
43
- import static nokogiri.internals.NokogiriHelpers.nonEmptyStringOrNil;
44
- import static nokogiri.internals.NokogiriHelpers.rubyStringToString;
45
- import static nokogiri.internals.NokogiriHelpers.stringOrNil;
36
+ import static nokogiri.internals.NokogiriHelpers.*;
46
37
 
47
38
  import java.io.ByteArrayInputStream;
48
39
  import java.io.InputStream;
49
40
  import java.nio.ByteBuffer;
50
41
  import java.nio.charset.Charset;
51
- import java.util.ArrayList;
52
- import java.util.Iterator;
53
- import java.util.List;
42
+ import java.util.*;
54
43
 
55
44
  import org.apache.xerces.dom.CoreDocumentImpl;
56
45
  import org.jruby.Ruby;
@@ -64,8 +53,8 @@ import org.jruby.RubyString;
64
53
  import org.jruby.anno.JRubyClass;
65
54
  import org.jruby.anno.JRubyMethod;
66
55
  import org.jruby.exceptions.RaiseException;
67
- import org.jruby.runtime.Helpers;
68
56
  import org.jruby.runtime.Block;
57
+ import org.jruby.runtime.Helpers;
69
58
  import org.jruby.runtime.ThreadContext;
70
59
  import org.jruby.runtime.Visibility;
71
60
  import org.jruby.runtime.builtin.IRubyObject;
@@ -102,8 +91,8 @@ public class XmlNode extends RubyObject {
102
91
 
103
92
  /* Cached objects */
104
93
  protected IRubyObject content = null;
105
- protected IRubyObject doc = null;
106
- protected IRubyObject name = null;
94
+ private transient XmlDocument doc;
95
+ protected transient RubyString name;
107
96
 
108
97
  /*
109
98
  * Taken from http://ejohn.org/blog/comparing-document-position/
@@ -124,7 +113,7 @@ public class XmlNode extends RubyObject {
124
113
  */
125
114
  protected static XmlNode asXmlNode(ThreadContext context, IRubyObject node) {
126
115
  if ( !(node instanceof XmlNode) ) {
127
- final Ruby runtime = context.getRuntime();
116
+ final Ruby runtime = context.runtime;
128
117
  throw runtime.newTypeError(node == null ? runtime.getNil() : node, getNokogiriClass(runtime, "Nokogiri::XML::Node"));
129
118
  }
130
119
  return (XmlNode) node;
@@ -206,29 +195,25 @@ public class XmlNode extends RubyObject {
206
195
  * This is the allocator for XmlNode class. It should only be
207
196
  * called from Ruby code.
208
197
  */
209
- public XmlNode(Ruby ruby, RubyClass cls) {
210
- super(ruby, cls);
198
+ public XmlNode(Ruby runtime, RubyClass klass) {
199
+ super(runtime, klass);
211
200
  }
212
201
 
213
202
  /**
214
203
  * This is a constructor to create an XmlNode from an already
215
204
  * existing node. It may be called by Java code.
216
205
  */
217
- public XmlNode(Ruby ruby, RubyClass cls, Node node) {
218
- super(ruby, cls);
219
- setNode(ruby.getCurrentContext(), node);
206
+ public XmlNode(Ruby runtime, RubyClass klass, Node node) {
207
+ super(runtime, klass);
208
+ setNode(runtime, node);
220
209
  }
221
210
 
222
- protected void decorate(final ThreadContext context) {
211
+ protected void decorate(final Ruby runtime) {
223
212
  if (node != null) {
224
213
  resetCache();
225
214
 
226
215
  if (node.getNodeType() != Node.DOCUMENT_NODE) {
227
- doc = document(context.runtime);
228
-
229
- if (doc != null && ! doc.isNil()) {
230
- Helpers.invoke(context, doc, "decorate", this);
231
- }
216
+ setDocumentAndDecorate(runtime.getCurrentContext(), this, document(runtime));
232
217
  }
233
218
  }
234
219
  }
@@ -287,7 +272,7 @@ public class XmlNode extends RubyObject {
287
272
  @JRubyMethod(name = "new", meta = true, rest = true)
288
273
  public static IRubyObject rbNew(ThreadContext context, IRubyObject cls,
289
274
  IRubyObject[] args, Block block) {
290
- Ruby ruby = context.getRuntime();
275
+ Ruby ruby = context.runtime;
291
276
  RubyClass klazz = (RubyClass) cls;
292
277
 
293
278
  if ("Nokogiri::XML::Node".equals(klazz.getName())) {
@@ -320,14 +305,14 @@ public class XmlNode extends RubyObject {
320
305
  */
321
306
  protected void init(ThreadContext context, IRubyObject[] args) {
322
307
  if (args.length < 2)
323
- throw context.getRuntime().newArgumentError(args.length, 2);
308
+ throw context.runtime.newArgumentError(args.length, 2);
324
309
 
325
310
  IRubyObject name = args[0];
326
311
  IRubyObject doc = args[1];
327
312
 
328
313
  Document document = asXmlNode(context, doc).getOwnerDocument();
329
314
  if (document == null) {
330
- throw getRuntime().newArgumentError("node must have owner document");
315
+ throw context.runtime.newArgumentError("node must have owner document");
331
316
  }
332
317
 
333
318
  Element element;
@@ -338,7 +323,7 @@ public class XmlNode extends RubyObject {
338
323
  namespace_uri = document.getDocumentElement().lookupNamespaceURI(prefix);
339
324
  }
340
325
  element = document.createElementNS(namespace_uri, node_name);
341
- setNode(context, element);
326
+ setNode(context.runtime, element);
342
327
  }
343
328
 
344
329
  /**
@@ -365,53 +350,6 @@ public class XmlNode extends RubyObject {
365
350
  return node;
366
351
  }
367
352
 
368
- public static Node getNodeFromXmlNode(ThreadContext context, IRubyObject xmlNode) {
369
- return asXmlNode(context, xmlNode).node;
370
- }
371
-
372
- protected String indentString(IRubyObject indentStringObject, String xml) {
373
- String[] lines = xml.split("\n");
374
-
375
- if(lines.length <= 1) return xml;
376
-
377
- String[] resultLines = new String[lines.length];
378
-
379
- String curLine;
380
- boolean closingTag = false;
381
- String indentString = rubyStringToString(indentStringObject);
382
- int lengthInd = indentString.length();
383
- StringBuilder curInd = new StringBuilder();
384
-
385
- resultLines[0] = lines[0];
386
-
387
- for(int i = 1; i < lines.length; i++) {
388
-
389
- curLine = lines[i].trim();
390
-
391
- if(curLine.length() == 0) continue;
392
-
393
- if(curLine.startsWith("</")) {
394
- closingTag = true;
395
- curInd.setLength(max(0,curInd.length() - lengthInd));
396
- }
397
-
398
- resultLines[i] = curInd.toString() + curLine;
399
-
400
- if(!curLine.endsWith("/>") && !closingTag) {
401
- curInd.append(indentString);
402
- }
403
-
404
- closingTag = false;
405
- }
406
-
407
- StringBuilder result = new StringBuilder();
408
- for(int i = 0; i < resultLines.length; i++) {
409
- result.append(resultLines[i]).append('\n');
410
- }
411
-
412
- return result.toString();
413
- }
414
-
415
353
  public boolean isComment() { return false; }
416
354
 
417
355
  public boolean isElement() {
@@ -431,7 +369,7 @@ public class XmlNode extends RubyObject {
431
369
  * declarations like XmlElementDecl.
432
370
  */
433
371
  protected IRubyObject getAttribute(ThreadContext context, String key) {
434
- return getAttribute(context.getRuntime(), key);
372
+ return getAttribute(context.runtime, key);
435
373
  }
436
374
 
437
375
  protected IRubyObject getAttribute(Ruby runtime, String key) {
@@ -472,9 +410,7 @@ public class XmlNode extends RubyObject {
472
410
  String nsURI = e.lookupNamespaceURI(prefix);
473
411
  this.node = NokogiriHelpers.renameNode(e, nsURI, e.getNodeName());
474
412
 
475
- if (nsURI == null || nsURI == "") {
476
- return;
477
- }
413
+ if (nsURI == null || nsURI.isEmpty()) return;
478
414
 
479
415
  String currentPrefix = e.getParentNode().lookupPrefix(nsURI);
480
416
  String currentURI = e.getParentNode().lookupNamespaceURI(prefix);
@@ -483,18 +419,15 @@ public class XmlNode extends RubyObject {
483
419
  // add xmlns attribute if this is a new root node or if the node's
484
420
  // namespace isn't a default namespace in the new document
485
421
  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);
422
+ // this is the root node, so we must set the namespaces attributes anyway
423
+ e.setAttribute(prefix == null ? "xmlns" : "xmlns:" + prefix, nsURI);
489
424
  } 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);
425
+ // this is a default namespace but isn't the default where this node is being added
426
+ if (!isDefault) e.setAttribute("xmlns", nsURI);
427
+ } else if (!prefix.equals(currentPrefix) || nsURI.equals(currentURI)) {
428
+ // this is a prefixed namespace
429
+ // but doesn't have the same prefix or the prefix is set to a different URI
430
+ e.setAttribute("xmlns:" + prefix, nsURI);
498
431
  }
499
432
 
500
433
  if (e.hasAttributes()) {
@@ -516,87 +449,76 @@ public class XmlNode extends RubyObject {
516
449
  nsUri = attr.lookupNamespaceURI(attrPrefix);
517
450
  }
518
451
 
519
- if (nsUri == e.getNamespaceURI()) {
452
+ if (nsUri != null && nsUri.equals(e.getNamespaceURI())) {
520
453
  nsUri = null;
521
454
  }
522
455
 
523
456
  if (!(nsUri == null || "".equals(nsUri) || "http://www.w3.org/XML/1998/namespace".equals(nsUri))) {
524
- // Create a new namespace object and add it to the document
525
- // namespace cache.
457
+ // Create a new namespace object and add it to the document namespace cache.
526
458
  // TODO: why do we need the namespace cache ?
527
- XmlNamespace.createFromAttr(context.getRuntime(), attr);
459
+ XmlNamespace.createFromAttr(context.runtime, attr);
528
460
  }
529
461
  NokogiriHelpers.renameNode(attr, nsUri, nodeName);
530
462
  }
531
463
  }
532
464
 
533
465
  if (this.node.hasChildNodes()) {
534
- XmlNodeSet nodeSet = (XmlNodeSet)(children(context));
535
- nodeSet.relink_namespace(context);
466
+ relink_namespace(context, getChildren());
467
+ }
468
+ }
469
+
470
+ static void relink_namespace(ThreadContext context, IRubyObject[] nodes) {
471
+ for (int i = 0; i < nodes.length; i++) {
472
+ if (nodes[i] instanceof XmlNode) {
473
+ ((XmlNode) nodes[i]).relink_namespace(context);
474
+ }
536
475
  }
537
476
  }
538
477
 
539
478
  // Users might extend XmlNode. This method works for such a case.
540
479
  public void accept(ThreadContext context, SaveContextVisitor visitor) {
541
480
  visitor.enter(node);
542
- XmlNodeSet xmlNodeSet = (XmlNodeSet) children(context);
543
- if (xmlNodeSet.length() > 0) {
544
- RubyArray array = (RubyArray) xmlNodeSet.to_a(context);
545
- for(int i = 0; i < array.getLength(); i++) {
546
- Object item = array.get(i);
481
+ acceptChildren(context, getChildren(), visitor);
482
+ visitor.leave(node);
483
+ }
484
+
485
+ void acceptChildren(ThreadContext context, IRubyObject[] nodes, SaveContextVisitor visitor) {
486
+ if (nodes.length > 0) {
487
+ for (int i = 0; i < nodes.length; i++) {
488
+ Object item = nodes[i];
547
489
  if (item instanceof XmlNode) {
548
- XmlNode cur = (XmlNode) item;
549
- cur.accept(context, visitor);
490
+ ((XmlNode) item).accept(context, visitor);
550
491
  } else if (item instanceof XmlNamespace) {
551
- XmlNamespace cur = (XmlNamespace)item;
552
- cur.accept(context, visitor);
492
+ ((XmlNamespace) item).accept(context, visitor);
553
493
  }
554
494
  }
555
495
  }
556
- visitor.leave(node);
557
496
  }
558
497
 
559
- public void setName(IRubyObject name) {
560
- this.name = name;
498
+ RubyString doSetName(IRubyObject name) {
499
+ if (name.isNil()) return this.name = null;
500
+ return this.name = name.convertToString();
561
501
  }
562
502
 
563
- public void setDocument(ThreadContext context, IRubyObject doc) {
503
+ public void setDocument(ThreadContext context, XmlDocument doc) {
564
504
  this.doc = doc;
565
505
 
566
506
  setDocumentAndDecorate(context, this, doc);
567
507
  }
568
508
 
569
509
  // shared logic with XmlNodeSet
570
- static void setDocumentAndDecorate(ThreadContext context, RubyObject self, IRubyObject doc) {
571
- self.setInstanceVariable("@document", doc);
572
- if (doc != null) {
573
- Helpers.invoke(context, doc, "decorate", self);
574
- }
510
+ static void setDocumentAndDecorate(ThreadContext context, RubyObject self, XmlDocument doc) {
511
+ self.setInstanceVariable("@document", doc == null ? context.nil : doc);
512
+ if (doc != null) Helpers.invoke(context, doc, "decorate", self);
575
513
  }
576
514
 
577
- public void setNode(ThreadContext context, Node node) {
515
+ public void setNode(Ruby runtime, Node node) {
578
516
  this.node = node;
579
517
 
580
- decorate(context);
518
+ decorate(runtime);
581
519
 
582
520
  if (this instanceof XmlAttr) {
583
- ((XmlAttr)this).setNamespaceIfNecessary(context.getRuntime());
584
- }
585
- }
586
-
587
- public void updateNodeNamespaceIfNecessary(ThreadContext context, XmlNamespace ns) {
588
- String oldPrefix = this.node.getPrefix();
589
- String uri = rubyStringToString(ns.href(context));
590
-
591
- /*
592
- * Update if both prefixes are null or equal
593
- */
594
- boolean update = (oldPrefix == null && ns.prefix(context).isNil()) ||
595
- (oldPrefix != null && !ns.prefix(context).isNil()
596
- && oldPrefix.equals(rubyStringToString(ns.prefix(context))));
597
-
598
- if(update) {
599
- this.node = NokogiriHelpers.renameNode(this.node, uri, this.node.getNodeName());
521
+ ((XmlAttr) this).setNamespaceIfNecessary(runtime);
600
522
  }
601
523
  }
602
524
 
@@ -605,12 +527,11 @@ public class XmlNode extends RubyObject {
605
527
 
606
528
  String str = null;
607
529
  if (node != null) {
608
- str = node.getNodeName();
609
- str = NokogiriHelpers.getLocalPart(str);
530
+ str = NokogiriHelpers.getLocalPart(node.getNodeName());
610
531
  }
611
532
  if (str == null) str = "";
612
- if (str.startsWith("#")) str = str.substring(1); // eliminates '#'
613
- return name = NokogiriHelpers.stringOrBlank(context.getRuntime(), str);
533
+ if (str.startsWith("#")) str = str.substring(1); // eliminates '#'
534
+ return name = context.runtime.newString(str);
614
535
  }
615
536
 
616
537
  /**
@@ -619,26 +540,20 @@ public class XmlNode extends RubyObject {
619
540
  * <code>xmlns:prefix="uri"</code>.
620
541
  */
621
542
  @JRubyMethod(name = {"add_namespace_definition", "add_namespace"})
622
- public IRubyObject add_namespace_definition(ThreadContext context,
623
- IRubyObject prefix,
624
- IRubyObject href) {
625
- String prefixString = rubyStringToString(prefix);
626
- String hrefString ;
543
+ public IRubyObject add_namespace_definition(ThreadContext context, IRubyObject prefix, IRubyObject href) {
544
+ String hrefStr, prefixStr = prefix.isNil() ? null : prefix.convertToString().decodeString();
627
545
 
628
546
  // try to search the namespace first
629
547
  if (href.isNil()) {
630
- hrefString = this.findNamespaceHref(context, rubyStringToString(prefix));
631
- if (hrefString == null) {
632
- return context.nil;
633
- }
634
- href = context.getRuntime().newString(hrefString);
548
+ hrefStr = findNamespaceHref(context, prefixStr);
549
+ if (hrefStr == null) return context.nil;
550
+ href = context.runtime.newString(hrefStr);
635
551
  } else {
636
- hrefString = rubyStringToString(href);
552
+ hrefStr = rubyStringToString(href.convertToString());
637
553
  }
638
554
 
639
- NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCacheFormNode(node);
640
- XmlNamespace cachedNamespace = nsCache.get(prefixString, hrefString);
641
-
555
+ NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCache(node);
556
+ XmlNamespace cachedNamespace = nsCache.get(prefixStr, hrefStr);
642
557
  if (cachedNamespace != null) return cachedNamespace;
643
558
 
644
559
  Node namespaceOwner;
@@ -646,48 +561,58 @@ public class XmlNode extends RubyObject {
646
561
  namespaceOwner = node;
647
562
  Element element = (Element) node;
648
563
  // adds namespace as node's attribute
649
- final String uri = "http://www.w3.org/2000/xmlns/";
650
- String qName =
651
- prefix.isNil() ? "xmlns" : "xmlns:" + prefixString;
652
-
653
- element.setAttributeNS(uri, qName, hrefString);
564
+ String qName = prefix.isNil() ? "xmlns" : "xmlns:" + prefixStr;
565
+ element.setAttributeNS("http://www.w3.org/2000/xmlns/", qName, hrefStr);
654
566
  }
655
- else if (node.getNodeType() == Node.ATTRIBUTE_NODE) namespaceOwner = ((Attr)node).getOwnerElement();
567
+ else if (node.getNodeType() == Node.ATTRIBUTE_NODE) namespaceOwner = ((Attr) node).getOwnerElement();
656
568
  else namespaceOwner = node.getParentNode();
657
- XmlNamespace ns = XmlNamespace.createFromPrefixAndHref(namespaceOwner, prefix, href);
658
- if (node != namespaceOwner) {
659
569
 
660
- this.node = NokogiriHelpers.renameNode(node, ns.getHref(), ns.getPrefix() + ":" + node.getLocalName());
570
+ XmlNamespace ns = XmlNamespace.createImpl(namespaceOwner, prefix, prefixStr, href, hrefStr);
571
+
572
+ if (node != namespaceOwner) {
573
+ node = NokogiriHelpers.renameNode(node, ns.getHref(), ns.getPrefix() + ':' + node.getLocalName());
661
574
  }
662
- updateNodeNamespaceIfNecessary(context, ns);
575
+ updateNodeNamespaceIfNecessary(ns);
663
576
 
664
577
  return ns;
665
578
  }
666
579
 
580
+ private void updateNodeNamespaceIfNecessary(XmlNamespace ns) {
581
+ String oldPrefix = this.node.getPrefix();
582
+
583
+ /*
584
+ * Update if both prefixes are null or equal
585
+ */
586
+ boolean update =
587
+ (oldPrefix == null && ns.getPrefix() == null) ||
588
+ (oldPrefix != null && oldPrefix.equals(ns.getPrefix()));
589
+
590
+ if (update) {
591
+ this.node = NokogiriHelpers.renameNode(this.node, ns.getHref(), this.node.getNodeName());
592
+ }
593
+ }
594
+
667
595
  @JRubyMethod(name = {"attribute", "attr"})
668
596
  public IRubyObject attribute(ThreadContext context, IRubyObject name){
669
597
  NamedNodeMap attrs = this.node.getAttributes();
670
598
  Node attr = attrs.getNamedItem(rubyStringToString(name));
671
- if(attr == null) {
672
- return context.getRuntime().getNil();
673
- }
674
- return getCachedNodeOrCreate(context.getRuntime(), attr);
599
+ if (attr == null) return context.nil;
600
+ return getCachedNodeOrCreate(context.runtime, attr);
675
601
  }
676
602
 
677
603
  @JRubyMethod
678
604
  public IRubyObject attribute_nodes(ThreadContext context) {
679
- NamedNodeMap nodeMap = this.node.getAttributes();
605
+ final Ruby runtime = context.runtime;
680
606
 
681
- Ruby ruby = context.getRuntime();
682
- if(nodeMap == null){
683
- return ruby.newEmptyArray();
684
- }
607
+ NamedNodeMap nodeMap = this.node.getAttributes();
685
608
 
686
- RubyArray attr = ruby.newArray();
609
+ if (nodeMap == null) return runtime.newEmptyArray();
610
+ RubyArray attr = runtime.newArray(nodeMap.getLength());
687
611
 
688
- for(int i = 0; i < nodeMap.getLength(); i++) {
612
+ final XmlDocument doc = document(context.runtime);
613
+ for (int i = 0; i < nodeMap.getLength(); i++) {
689
614
  if ((doc instanceof HtmlDocument) || !NokogiriHelpers.isNamespace(nodeMap.item(i))) {
690
- attr.append(getCachedNodeOrCreate(context.getRuntime(), nodeMap.item(i)));
615
+ attr.append(getCachedNodeOrCreate(runtime, nodeMap.item(i)));
691
616
  }
692
617
  }
693
618
 
@@ -701,10 +626,9 @@ public class XmlNode extends RubyObject {
701
626
 
702
627
  Node el = this.node.getAttributes().getNamedItemNS(nsj, namej);
703
628
 
704
- if(el == null) {
705
- return context.getRuntime().getNil();
706
- }
707
- return NokogiriHelpers.getCachedNodeOrCreate(context.getRuntime(), el);
629
+ if (el == null) return context.nil;
630
+
631
+ return NokogiriHelpers.getCachedNodeOrCreate(context.runtime, el);
708
632
  }
709
633
 
710
634
  @JRubyMethod(name = "blank?")
@@ -725,55 +649,58 @@ public class XmlNode extends RubyObject {
725
649
 
726
650
  @JRubyMethod
727
651
  public IRubyObject children(ThreadContext context) {
728
- XmlNodeSet xmlNodeSet = XmlNodeSet.newEmptyNodeSet(context);
652
+ final IRubyObject[] nodes = getChildren();
653
+ if (nodes.length == 0) {
654
+ return XmlNodeSet.newEmptyNodeSet(context, this);
655
+ }
656
+ return XmlNodeSet.newNodeSet(context.runtime, nodes);
657
+ }
729
658
 
659
+ IRubyObject[] getChildren() {
730
660
  NodeList nodeList = node.getChildNodes();
731
661
  if (nodeList.getLength() > 0) {
732
- xmlNodeSet.setNodeList(nodeList); // initializes @document from first node
733
- }
734
- else { // TODO this is very ripe for refactoring
735
- setDocumentAndDecorate(context, xmlNodeSet, doc);
662
+ return nodeListToRubyArray(getRuntime(), nodeList);
736
663
  }
737
-
738
- return xmlNodeSet;
664
+ return IRubyObject.NULL_ARRAY;
739
665
  }
740
666
 
741
667
  @JRubyMethod
742
668
  public IRubyObject first_element_child(ThreadContext context) {
743
- List<Node> elementNodes = new ArrayList<Node>();
744
- addElements(node, elementNodes, true);
745
- if (elementNodes.size() == 0) return context.getRuntime().getNil();
746
- return getCachedNodeOrCreate(context.getRuntime(), elementNodes.get(0));
669
+ List<Node> elementNodes = getElements(node, true);
670
+ if (elementNodes.size() == 0) return context.nil;
671
+ return getCachedNodeOrCreate(context.runtime, elementNodes.get(0));
747
672
  }
748
673
 
749
674
  @JRubyMethod
750
675
  public IRubyObject last_element_child(ThreadContext context) {
751
- List<Node> elementNodes = new ArrayList<Node>();
752
- addElements(node, elementNodes, false);
753
- if (elementNodes.size() == 0) return context.getRuntime().getNil();
754
- return getCachedNodeOrCreate(context.getRuntime(), elementNodes.get(elementNodes.size()-1));
676
+ List<Node> elementNodes = getElements(node, false);
677
+ if (elementNodes.size() == 0) return context.nil;
678
+ return getCachedNodeOrCreate(context.runtime, elementNodes.get(elementNodes.size() - 1));
755
679
  }
756
680
 
757
681
  @JRubyMethod(name = {"element_children", "elements"})
758
682
  public IRubyObject element_children(ThreadContext context) {
759
- List<Node> elementNodes = new ArrayList<Node>();
760
- addElements(node, elementNodes, false);
761
- IRubyObject[] array = NokogiriHelpers.nodeArrayToArray(context.runtime,
762
- elementNodes.toArray(new Node[0]));
763
- XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, array);
764
- return xmlNodeSet;
683
+ List<Node> elementNodes = getElements(node, false);
684
+ IRubyObject[] array = NokogiriHelpers.nodeListToArray(context.runtime, elementNodes);
685
+ return XmlNodeSet.newNodeSet(context.runtime, array, this);
765
686
  }
766
687
 
767
- private void addElements(Node n, List<Node> nodes, boolean isFirstOnly) {
768
- NodeList children = n.getChildNodes();
769
- if (children.getLength() == 0) return;
688
+ private static List<Node> getElements(Node node, final boolean firstOnly) {
689
+ NodeList children = node.getChildNodes();
690
+ if (children.getLength() == 0) {
691
+ return Collections.emptyList();
692
+ }
693
+ ArrayList<Node> elements = firstOnly ? null : new ArrayList<Node>(children.getLength());
770
694
  for (int i=0; i< children.getLength(); i++) {
771
695
  Node child = children.item(i);
772
696
  if (child.getNodeType() == Node.ELEMENT_NODE) {
773
- nodes.add(child);
774
- if (isFirstOnly) return;
697
+ if (firstOnly) {
698
+ return Collections.singletonList(child);
699
+ }
700
+ elements.add(child);
775
701
  }
776
702
  }
703
+ return elements;
777
704
  }
778
705
 
779
706
  /**
@@ -785,7 +712,7 @@ public class XmlNode extends RubyObject {
785
712
  @JRubyMethod(visibility=Visibility.PRIVATE)
786
713
  public IRubyObject compare(ThreadContext context, IRubyObject other) {
787
714
  if (!(other instanceof XmlNode)) {
788
- return context.getRuntime().newFixnum(-2);
715
+ return context.runtime.newFixnum(-2);
789
716
  }
790
717
 
791
718
  Node otherNode = asXmlNode(context, other).node;
@@ -793,22 +720,22 @@ public class XmlNode extends RubyObject {
793
720
  // Do not touch this if, if it's not for a good reason.
794
721
  if (node.getNodeType() == Node.DOCUMENT_NODE ||
795
722
  otherNode.getNodeType() == Node.DOCUMENT_NODE) {
796
- return context.getRuntime().newFixnum(-1);
723
+ return context.runtime.newFixnum(-1);
797
724
  }
798
725
 
799
726
  try{
800
727
  int res = node.compareDocumentPosition(otherNode);
801
728
  if ((res & FIRST_PRECEDES_SECOND) == FIRST_PRECEDES_SECOND) {
802
- return context.getRuntime().newFixnum(-1);
729
+ return context.runtime.newFixnum(-1);
803
730
  } else if ((res & SECOND_PRECEDES_FIRST) == SECOND_PRECEDES_FIRST) {
804
- return context.getRuntime().newFixnum(1);
731
+ return context.runtime.newFixnum(1);
805
732
  } else if (res == IDENTICAL_ELEMENTS) {
806
- return context.getRuntime().newFixnum(0);
733
+ return context.runtime.newFixnum(0);
807
734
  }
808
735
 
809
- return context.getRuntime().newFixnum(-2);
736
+ return context.runtime.newFixnum(-2);
810
737
  } catch (Exception ex) {
811
- return context.getRuntime().newFixnum(-2);
738
+ return context.runtime.newFixnum(-2);
812
739
  }
813
740
  }
814
741
 
@@ -818,26 +745,20 @@ public class XmlNode extends RubyObject {
818
745
  * <code>options</code> into account.
819
746
  */
820
747
  @JRubyMethod(required = 2, visibility = Visibility.PRIVATE)
821
- public IRubyObject in_context(ThreadContext context,
822
- IRubyObject str,
823
- IRubyObject options) {
824
- RubyModule klass;
748
+ public IRubyObject in_context(ThreadContext context, IRubyObject str, IRubyObject options) {
749
+ RubyClass klass;
825
750
  XmlDomParserContext ctx;
826
751
  InputStream istream;
827
- XmlDocument document;
828
752
 
829
- IRubyObject d = document(context);
830
- Ruby runtime = context.getRuntime();
831
- if (d != null && d instanceof XmlDocument) {
832
- document = (XmlDocument)d;
833
- } else {
834
- return runtime.getNil();
835
- }
753
+ final Ruby runtime = context.runtime;
754
+
755
+ XmlDocument document = document(runtime);
756
+ if (document == null) return context.nil;
836
757
 
837
758
  if (document instanceof HtmlDocument) {
838
759
  klass = getNokogiriClass(runtime, "Nokogiri::HTML::Document");
839
760
  ctx = new HtmlDomParserContext(runtime, options);
840
- ((HtmlDomParserContext)ctx).enableDocumentFragment();
761
+ ((HtmlDomParserContext) ctx).enableDocumentFragment();
841
762
  istream = new ByteArrayInputStream((rubyStringToString(str)).getBytes());
842
763
  } else {
843
764
  klass = getNokogiriClass(runtime, "Nokogiri::XML::Document");
@@ -854,17 +775,16 @@ public class XmlNode extends RubyObject {
854
775
  htmlCtx.setEncoding(document.getEncoding().asJavaString());
855
776
  }
856
777
 
857
- XmlDocument doc = ctx.parse(context, klass, runtime.getNil());
778
+ XmlDocument doc = ctx.parse(context, klass, context.nil);
858
779
 
859
- RubyArray documentErrors = getErrorArray(document);
860
- RubyArray docErrors = getErrorArray(doc);
861
- if (isErrorIncreased(documentErrors, docErrors)) {
780
+ RubyArray documentErrors = getErrors(document);
781
+ RubyArray docErrors = getErrors(doc);
782
+ if (checkNewErrors(documentErrors, docErrors)) {
862
783
  for (int i = 0; i < docErrors.getLength(); i++) {
863
- documentErrors.add(docErrors.entry(i));
784
+ documentErrors.append(docErrors.entry(i));
864
785
  }
865
786
  document.setInstanceVariable("@errors", documentErrors);
866
- XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, new IRubyObject[0]);
867
- return xmlNodeSet;
787
+ return XmlNodeSet.newNodeSet(context.runtime, IRubyObject.NULL_ARRAY, this);
868
788
  }
869
789
 
870
790
  // The first child might be document type node (dtd declaration).
@@ -876,27 +796,24 @@ public class XmlNode extends RubyObject {
876
796
  first = doc.node.getFirstChild();
877
797
  }
878
798
 
879
- IRubyObject[] nodes = new IRubyObject[]{NokogiriHelpers.getCachedNodeOrCreate(runtime, first)};
880
- XmlNodeSet xmlNodeSet = XmlNodeSet.newXmlNodeSet(context, nodes);
881
- return xmlNodeSet;
799
+ IRubyObject[] nodes = new IRubyObject[] { NokogiriHelpers.getCachedNodeOrCreate(runtime, first) };
800
+ return XmlNodeSet.newNodeSet(context.runtime, nodes, this);
882
801
  }
883
802
 
884
- private RubyArray getErrorArray(XmlDocument document) {
803
+ private static RubyArray getErrors(XmlDocument document) {
885
804
  IRubyObject obj = document.getInstanceVariable("@errors");
886
- if (obj != null && obj instanceof RubyArray) {
887
- return (RubyArray)obj;
888
- }
889
- return RubyArray.newArray(document.getRuntime());
805
+ if (obj instanceof RubyArray) return (RubyArray) obj;
806
+ return RubyArray.newEmptyArray(document.getRuntime());
890
807
  }
891
808
 
892
- private boolean isErrorIncreased(RubyArray baseErrors, RubyArray createdErrors) {
893
- int length = ((RubyArray) createdErrors.op_diff(baseErrors)).size();
809
+ private static boolean checkNewErrors(RubyArray baseErrors, RubyArray newErrors) {
810
+ int length = ((RubyArray) newErrors.op_diff(baseErrors)).size();
894
811
  return length > 0;
895
812
  }
896
813
 
897
814
  @JRubyMethod(name = {"content", "text", "inner_text"})
898
815
  public IRubyObject content(ThreadContext context) {
899
- return stringOrNil(context.getRuntime(), getContentImpl());
816
+ return stringOrNil(context.runtime, getContentImpl());
900
817
  }
901
818
 
902
819
  public CharSequence getContentImpl() {
@@ -906,7 +823,7 @@ public class XmlNode extends RubyObject {
906
823
  }
907
824
  CharSequence textContent;
908
825
  if (this instanceof XmlDocument) {
909
- Node node = ((Document)this.node).getDocumentElement();
826
+ Node node = ((Document) this.node).getDocumentElement();
910
827
  if (node == null) {
911
828
  textContent = "";
912
829
  } else {
@@ -920,7 +837,7 @@ public class XmlNode extends RubyObject {
920
837
  return textContent;
921
838
  }
922
839
 
923
- private StringBuilder getTextContentRecursively(StringBuilder buffer, Node currentNode) {
840
+ private static StringBuilder getTextContentRecursively(StringBuilder buffer, Node currentNode) {
924
841
  CharSequence textContent = currentNode.getNodeValue();
925
842
  if (textContent != null && NokogiriHelpers.shouldDecode(currentNode)) {
926
843
  textContent = NokogiriHelpers.decodeJavaString(textContent);
@@ -934,7 +851,7 @@ public class XmlNode extends RubyObject {
934
851
  return buffer;
935
852
  }
936
853
 
937
- private boolean hasTextContent(Node child) {
854
+ private static boolean hasTextContent(Node child) {
938
855
  return child.getNodeType() != Node.COMMENT_NODE && child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE;
939
856
  }
940
857
 
@@ -943,13 +860,17 @@ public class XmlNode extends RubyObject {
943
860
  return document(context.runtime);
944
861
  }
945
862
 
946
- IRubyObject document(final Ruby runtime) {
863
+ XmlDocument document(final Ruby runtime) {
864
+ return document(runtime, true);
865
+ }
866
+
867
+ XmlDocument document(final Ruby runtime, boolean create) {
947
868
  if (doc == null) {
948
869
  doc = (XmlDocument) node.getOwnerDocument().getUserData(NokogiriHelpers.CACHED_NODE);
949
- }
950
- if (doc == null) {
951
- doc = getCachedNodeOrCreate(runtime, node.getOwnerDocument());
952
- node.getOwnerDocument().setUserData(NokogiriHelpers.CACHED_NODE, doc, null);
870
+ if (doc == null && create) {
871
+ doc = (XmlDocument) getCachedNodeOrCreate(runtime, node.getOwnerDocument());
872
+ node.getOwnerDocument().setUserData(NokogiriHelpers.CACHED_NODE, doc, null);
873
+ }
953
874
  }
954
875
  return doc;
955
876
  }
@@ -970,7 +891,7 @@ public class XmlNode extends RubyObject {
970
891
  }
971
892
 
972
893
  protected final IRubyObject dup_implementation(ThreadContext context, boolean deep) {
973
- return dup_implementation(context.getRuntime(), deep);
894
+ return dup_implementation(context.runtime, deep);
974
895
  }
975
896
 
976
897
  protected IRubyObject dup_implementation(Ruby runtime, boolean deep) {
@@ -987,15 +908,14 @@ public class XmlNode extends RubyObject {
987
908
 
988
909
  public static RubyString encode_special_chars(ThreadContext context, IRubyObject string) {
989
910
  CharSequence str = NokogiriHelpers.encodeJavaString( rubyStringToString(string) );
990
- return RubyString.newString(context.getRuntime(), str);
911
+ return RubyString.newString(context.runtime, str);
991
912
  }
992
913
 
993
914
  /**
994
915
  * Instance method version of the above static method.
995
916
  */
996
917
  @JRubyMethod(name="encode_special_chars")
997
- public IRubyObject i_encode_special_chars(ThreadContext context,
998
- IRubyObject string) {
918
+ public IRubyObject i_encode_special_chars(ThreadContext context, IRubyObject string) {
999
919
  return encode_special_chars(context, string);
1000
920
  }
1001
921
 
@@ -1007,14 +927,14 @@ public class XmlNode extends RubyObject {
1007
927
  @JRubyMethod(visibility = Visibility.PRIVATE)
1008
928
  public IRubyObject get(ThreadContext context, IRubyObject rbkey) {
1009
929
  if (node instanceof Element) {
1010
- if (rbkey == null || rbkey.isNil()) context.getRuntime().getNil();
930
+ if (rbkey == null || rbkey.isNil()) return context.nil;
1011
931
  String key = rubyStringToString(rbkey);
1012
932
  Element element = (Element) node;
1013
- if (!element.hasAttribute(key)) return context.getRuntime().getNil();
933
+ if (!element.hasAttribute(key)) return context.nil;
1014
934
  String value = element.getAttribute(key);
1015
- return stringOrNil(context.getRuntime(), value);
935
+ return stringOrNil(context.runtime, value);
1016
936
  }
1017
- return context.getRuntime().getNil();
937
+ return context.nil;
1018
938
  }
1019
939
 
1020
940
  /**
@@ -1050,8 +970,7 @@ public class XmlNode extends RubyObject {
1050
970
  IRubyObject system_id) {
1051
971
  IRubyObject subset = internal_subset(context);
1052
972
  if (!subset.isNil()) {
1053
- throw context.getRuntime()
1054
- .newRuntimeError("Document already has internal subset");
973
+ throw context.runtime.newRuntimeError("Document already has internal subset");
1055
974
  }
1056
975
 
1057
976
  Document document = getOwnerDocument();
@@ -1087,8 +1006,7 @@ public class XmlNode extends RubyObject {
1087
1006
  IRubyObject system_id) {
1088
1007
  IRubyObject subset = external_subset(context);
1089
1008
  if (!subset.isNil()) {
1090
- throw context.getRuntime()
1091
- .newRuntimeError("Document already has external subset");
1009
+ throw context.runtime.newRuntimeError("Document already has external subset");
1092
1010
  }
1093
1011
 
1094
1012
  Document document = getOwnerDocument();
@@ -1110,42 +1028,40 @@ public class XmlNode extends RubyObject {
1110
1028
  String key = rubyStringToString(rbkey);
1111
1029
  Element element = (Element) node;
1112
1030
  if (element.hasAttribute(key)) {
1113
- return context.getRuntime().getTrue();
1031
+ return context.runtime.getTrue();
1114
1032
  } else {
1115
1033
  NamedNodeMap namedNodeMap = element.getAttributes();
1116
1034
  for (int i=0; i<namedNodeMap.getLength(); i++) {
1117
1035
  Node n = namedNodeMap.item(i);
1118
1036
  if (key.equals(n.getLocalName())) {
1119
- return context.getRuntime().getTrue();
1037
+ return context.runtime.getTrue();
1120
1038
  }
1121
1039
  }
1122
1040
  }
1123
- return context.getRuntime().getFalse();
1124
- } else {
1125
- return context.getRuntime().getNil();
1041
+ return context.runtime.getFalse();
1126
1042
  }
1043
+ return context.nil;
1127
1044
  }
1128
1045
 
1129
1046
  @JRubyMethod
1130
1047
  public IRubyObject namespace(ThreadContext context) {
1131
- Ruby runtime = context.getRuntime();
1132
- if (doc instanceof HtmlDocument) return runtime.getNil();
1133
- NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCacheFormNode(node);
1048
+ final XmlDocument doc = document(context.runtime);
1049
+ if (doc instanceof HtmlDocument) return context.nil;
1050
+
1134
1051
  String namespaceURI = node.getNamespaceURI();
1135
- if (namespaceURI == null || namespaceURI == "") {
1136
- return runtime.getNil();
1052
+ if (namespaceURI == null || namespaceURI.isEmpty()) {
1053
+ return context.nil;
1137
1054
  }
1138
1055
 
1139
1056
  String prefix = node.getPrefix();
1140
- XmlNamespace namespace = nsCache.get(prefix == null ? "" : prefix, namespaceURI);
1057
+ NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCache(node);
1058
+ XmlNamespace namespace = nsCache.get(prefix, namespaceURI);
1059
+
1141
1060
  if (namespace == null || namespace.isEmpty()) {
1142
- // if it's not in the cache, create an unowned, uncached namespace and
1143
- // return that. XmlReader can't insert namespaces into the cache, so
1144
- // this is necessary for XmlReader to work correctly.
1145
- namespace = new XmlNamespace(runtime, getNokogiriClass(runtime, "Nokogiri::XML::Namespace"));
1146
- IRubyObject rubyPrefix = NokogiriHelpers.stringOrNil(runtime, prefix);
1147
- IRubyObject rubyUri = NokogiriHelpers.stringOrNil(runtime, namespaceURI);
1148
- namespace.init(null, rubyPrefix, rubyUri, doc);
1061
+ // if it's not in the cache, create an unowned, uncached namespace and
1062
+ // return that. XmlReader can't insert namespaces into the cache, so
1063
+ // this is necessary for XmlReader to work correctly.
1064
+ namespace = new XmlNamespace(context.runtime, null, prefix, namespaceURI, doc);
1149
1065
  }
1150
1066
 
1151
1067
  return namespace;
@@ -1159,18 +1075,14 @@ public class XmlNode extends RubyObject {
1159
1075
  public IRubyObject namespace_definitions(ThreadContext context) {
1160
1076
  // don't use namespace_definitions cache anymore since
1161
1077
  // namespaces might be deleted. Reflecting the result of
1162
- // namesapce removals is complicated, so the cache might not be
1078
+ // namespace removals is complicated, so the cache might not be
1163
1079
  // updated.
1164
- Ruby ruby = context.getRuntime();
1165
- RubyArray namespace_definitions = ruby.newArray();
1166
- if (doc == null) return namespace_definitions;
1167
- if (doc instanceof HtmlDocument) return namespace_definitions;
1168
- List<XmlNamespace> namespaces = ((XmlDocument)doc).getNamespaceCache().get(node);
1169
- for (XmlNamespace namespace : namespaces) {
1170
- namespace_definitions.append(namespace);
1171
- }
1080
+ final XmlDocument doc = document(context.runtime);
1081
+ if (doc == null) return context.runtime.newEmptyArray();
1082
+ if (doc instanceof HtmlDocument) return context.runtime.newEmptyArray();
1172
1083
 
1173
- return namespace_definitions;
1084
+ List<XmlNamespace> namespaces = doc.getNamespaceCache().get(node);
1085
+ return context.runtime.newArray((List) namespaces);
1174
1086
  }
1175
1087
 
1176
1088
  /**
@@ -1178,10 +1090,10 @@ public class XmlNode extends RubyObject {
1178
1090
  * on any ancestor node.
1179
1091
  */
1180
1092
  @JRubyMethod
1181
- public IRubyObject namespace_scopes(ThreadContext context) {
1182
- RubyArray scoped_namespaces = context.getRuntime().newArray();
1183
- if (doc == null) return scoped_namespaces;
1184
- if (doc instanceof HtmlDocument) return scoped_namespaces;
1093
+ public RubyArray namespace_scopes(ThreadContext context) {
1094
+ final XmlDocument doc = document(context.runtime);
1095
+ if (doc == null) return context.runtime.newEmptyArray();
1096
+ if (doc instanceof HtmlDocument) return context.runtime.newEmptyArray();
1185
1097
 
1186
1098
  Node previousNode;
1187
1099
  if (node.getNodeType() == Node.ELEMENT_NODE) {
@@ -1191,11 +1103,12 @@ public class XmlNode extends RubyObject {
1191
1103
  } else {
1192
1104
  previousNode = findPreviousElement(node);
1193
1105
  }
1194
- if (previousNode == null) return scoped_namespaces;
1106
+ if (previousNode == null) return context.runtime.newEmptyArray();
1195
1107
 
1196
- List<String> prefixes_in_scope = new ArrayList<String>();
1197
- NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCacheFormNode(previousNode);
1198
- for (Node previous=previousNode; previous != null; ) {
1108
+ final RubyArray scoped_namespaces = context.runtime.newArray();
1109
+ final HashSet<String> prefixes_in_scope = new HashSet<String>(8);
1110
+ NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCache(previousNode);
1111
+ for (Node previous = previousNode; previous != null; ) {
1199
1112
  List<XmlNamespace> namespaces = nsCache.get(previous);
1200
1113
  for (XmlNamespace namespace : namespaces) {
1201
1114
  if (prefixes_in_scope.contains(namespace.getPrefix())) continue;
@@ -1220,7 +1133,7 @@ public class XmlNode extends RubyObject {
1220
1133
  @JRubyMethod(name="namespaced_key?")
1221
1134
  public IRubyObject namespaced_key_p(ThreadContext context, IRubyObject elementLName, IRubyObject namespaceUri) {
1222
1135
  return this.attribute_with_ns(context, elementLName, namespaceUri).isNil() ?
1223
- context.getRuntime().getFalse() : context.getRuntime().getTrue();
1136
+ context.runtime.getFalse() : context.runtime.getTrue();
1224
1137
  }
1225
1138
 
1226
1139
  protected void setContent(IRubyObject content) {
@@ -1249,12 +1162,12 @@ public class XmlNode extends RubyObject {
1249
1162
  IRubyObject currentObj = this ;
1250
1163
  while (!currentObj.isNil()) {
1251
1164
  XmlNode currentNode = asXmlNode(context, currentObj);
1252
- IRubyObject lang = currentNode.getAttribute(context.getRuntime(), "xml:lang");
1165
+ IRubyObject lang = currentNode.getAttribute(context.runtime, "xml:lang");
1253
1166
  if (!lang.isNil()) { return lang ; }
1254
1167
 
1255
1168
  currentObj = currentNode.parent(context);
1256
1169
  }
1257
- return context.nil ;
1170
+ return context.nil;
1258
1171
  }
1259
1172
 
1260
1173
  @JRubyMethod(name = "lang=")
@@ -1277,7 +1190,7 @@ public class XmlNode extends RubyObject {
1277
1190
  IRubyObject indentString = args[2];
1278
1191
  IRubyObject options = args[3];
1279
1192
 
1280
- String encString = encoding.isNil() ? null : rubyStringToString(encoding);
1193
+ String encString = rubyStringToString(encoding);
1281
1194
 
1282
1195
  SaveContextVisitor visitor =
1283
1196
  new SaveContextVisitor(RubyFixnum.fix2int(options), rubyStringToString(indentString), encString, isHtmlDoc(context), isFragment(), 0);
@@ -1285,11 +1198,11 @@ public class XmlNode extends RubyObject {
1285
1198
 
1286
1199
  final IRubyObject rubyString;
1287
1200
  if (NokogiriHelpers.isUTF8(encString)) {
1288
- rubyString = convertString(context.getRuntime(), visitor.getInternalBuffer());
1201
+ rubyString = convertString(context.runtime, visitor.getInternalBuffer());
1289
1202
  } else {
1290
1203
  ByteBuffer bytes = convertEncoding(Charset.forName(encString), visitor.getInternalBuffer());
1291
1204
  ByteList str = new ByteList(bytes.array(), bytes.arrayOffset(), bytes.remaining());
1292
- rubyString = RubyString.newString(context.getRuntime(), str);
1205
+ rubyString = RubyString.newString(context.runtime, str);
1293
1206
  }
1294
1207
  Helpers.invoke(context, io, "write", rubyString);
1295
1208
 
@@ -1297,7 +1210,7 @@ public class XmlNode extends RubyObject {
1297
1210
  }
1298
1211
 
1299
1212
  private boolean isHtmlDoc(ThreadContext context) {
1300
- return document(context).getMetaClass().isKindOfModule(getNokogiriClass(context.getRuntime(), "Nokogiri::HTML::Document"));
1213
+ return document(context).getMetaClass().isKindOfModule(getNokogiriClass(context.runtime, "Nokogiri::HTML::Document"));
1301
1214
  }
1302
1215
 
1303
1216
  private boolean isFragment() {
@@ -1316,14 +1229,6 @@ public class XmlNode extends RubyObject {
1316
1229
  return getCachedNodeOrCreate(context.getRuntime(), node.getPreviousSibling());
1317
1230
  }
1318
1231
 
1319
- @JRubyMethod(meta = true, rest = true)
1320
- public static IRubyObject new_from_str(ThreadContext context,
1321
- IRubyObject cls,
1322
- IRubyObject[] args) {
1323
- XmlDocument doc = (XmlDocument) XmlDocument.read_memory(context, args);
1324
- return doc.root(context);
1325
- }
1326
-
1327
1232
  @JRubyMethod(name = {"node_name", "name"})
1328
1233
  public IRubyObject node_name(ThreadContext context) {
1329
1234
  return getNodeName(context);
@@ -1331,9 +1236,9 @@ public class XmlNode extends RubyObject {
1331
1236
 
1332
1237
  @JRubyMethod(name = {"node_name=", "name="})
1333
1238
  public IRubyObject node_name_set(ThreadContext context, IRubyObject nodeName) {
1334
- String newName = rubyStringToString(nodeName);
1239
+ nodeName = doSetName(nodeName);
1240
+ String newName = nodeName == null ? null : rubyStringToString((RubyString) nodeName);
1335
1241
  this.node = NokogiriHelpers.renameNode(node, null, newName);
1336
- setName(nodeName);
1337
1242
  return this;
1338
1243
  }
1339
1244
 
@@ -1372,23 +1277,19 @@ public class XmlNode extends RubyObject {
1372
1277
  }
1373
1278
 
1374
1279
  private String findNamespaceHref(ThreadContext context, String prefix) {
1375
- XmlNode currentNode = this;
1376
- while(currentNode != document(context)) {
1377
- RubyArray namespaces = (RubyArray) currentNode.namespace_scopes(context);
1378
- Iterator iterator = namespaces.iterator();
1379
- while(iterator.hasNext()) {
1380
- XmlNamespace namespace = (XmlNamespace) iterator.next();
1381
- if (namespace.getPrefix().equals(prefix)) {
1382
- return namespace.getHref();
1383
- }
1384
- }
1385
- if (currentNode.parent(context).isNil()) {
1386
- break;
1387
- } else {
1388
- currentNode = (XmlNode) currentNode.parent(context);
1280
+ XmlNode currentNode = this;
1281
+ final XmlDocument doc = document(context.runtime);
1282
+ while (currentNode != doc) {
1283
+ RubyArray namespaces = currentNode.namespace_scopes(context);
1284
+ for (int i = 0; i<namespaces.size(); i++) {
1285
+ XmlNamespace namespace = (XmlNamespace) namespaces.eltInternal(i);
1286
+ if (namespace.hasPrefix(prefix)) return namespace.getHref();
1287
+ }
1288
+ IRubyObject parent = currentNode.parent(context);
1289
+ if (parent == context.nil) break;
1290
+ currentNode = (XmlNode) parent;
1389
1291
  }
1390
- }
1391
- return null;
1292
+ return null;
1392
1293
  }
1393
1294
 
1394
1295
  @JRubyMethod
@@ -1400,35 +1301,31 @@ public class XmlNode extends RubyObject {
1400
1301
  if (node.getOwnerDocument() != null &&
1401
1302
  node.getOwnerDocument().getDocumentElement() == node) {
1402
1303
  return document(context);
1403
- } else {
1404
- return getCachedNodeOrCreate(context.getRuntime(), node.getParentNode());
1405
1304
  }
1305
+ return getCachedNodeOrCreate(context.runtime, node.getParentNode());
1406
1306
  }
1407
1307
 
1408
1308
  @JRubyMethod
1409
1309
  public IRubyObject path(ThreadContext context) {
1410
- return RubyString.newString(context.getRuntime(), NokogiriHelpers.getNodeCompletePath(this.node));
1310
+ return RubyString.newString(context.runtime, NokogiriHelpers.getNodeCompletePath(this.node));
1411
1311
  }
1412
1312
 
1413
1313
  @JRubyMethod
1414
1314
  public IRubyObject pointer_id(ThreadContext context) {
1415
- return RubyFixnum.newFixnum(context.getRuntime(), this.node.hashCode());
1315
+ return RubyFixnum.newFixnum(context.runtime, this.node.hashCode());
1416
1316
  }
1417
1317
 
1418
1318
  @JRubyMethod(visibility=Visibility.PRIVATE)
1419
1319
  public IRubyObject set_namespace(ThreadContext context, IRubyObject namespace) {
1420
1320
  if (namespace.isNil()) {
1321
+ XmlDocument doc = document(context.runtime);
1421
1322
  if (doc != null) {
1422
- Node n = node;
1423
- String prefix = n.getPrefix();
1424
- String href = n.getNamespaceURI();
1425
- ((XmlDocument)doc).getNamespaceCache().remove(prefix == null ? "" : prefix, href);
1426
- this.node = NokogiriHelpers.renameNode(n, null, NokogiriHelpers.getLocalPart(n.getNodeName()));
1323
+ Node node = this.node;
1324
+ doc.getNamespaceCache().remove(node);
1325
+ this.node = NokogiriHelpers.renameNode(node, null, NokogiriHelpers.getLocalPart(node.getNodeName()));
1427
1326
  }
1428
1327
  } else {
1429
1328
  XmlNamespace ns = (XmlNamespace) namespace;
1430
- String prefix = rubyStringToString(ns.prefix(context));
1431
- String href = rubyStringToString(ns.href(context));
1432
1329
 
1433
1330
  // Assigning node = ...renameNode() or not seems to make no
1434
1331
  // difference. Why not? -pmahoney
@@ -1438,8 +1335,8 @@ public class XmlNode extends RubyObject {
1438
1335
  // The node you passed in *might* come back as you expect, but
1439
1336
  // it might not. It's much safer to throw away the original
1440
1337
  // and keep the return value. -mbklein
1441
- String new_name = NokogiriHelpers.newQName(prefix, node);
1442
- this.node = NokogiriHelpers.renameNode(node, href, new_name);
1338
+ String new_name = NokogiriHelpers.newQName(ns.getPrefix(), node);
1339
+ this.node = NokogiriHelpers.renameNode(node, ns.getHref(), new_name);
1443
1340
  }
1444
1341
 
1445
1342
  clearXpathContext(getNode());
@@ -1493,10 +1390,10 @@ public class XmlNode extends RubyObject {
1493
1390
  case Node.DOCUMENT_FRAGMENT_NODE: type = "DOCUMENT_FRAG_NODE"; break;
1494
1391
  case Node.NOTATION_NODE: type = "NOTATION_NODE"; break;
1495
1392
  default:
1496
- return context.getRuntime().newFixnum(0);
1393
+ return context.runtime.newFixnum(0);
1497
1394
  }
1498
1395
 
1499
- return getNokogiriClass(context.getRuntime(), "Nokogiri::XML::Node").getConstant(type);
1396
+ return getNokogiriClass(context.runtime, "Nokogiri::XML::Node").getConstant(type);
1500
1397
  }
1501
1398
 
1502
1399
  @JRubyMethod
@@ -1504,7 +1401,7 @@ public class XmlNode extends RubyObject {
1504
1401
  Node root = getOwnerDocument();
1505
1402
  int[] counter = new int[1];
1506
1403
  count(root, counter);
1507
- return RubyFixnum.newFixnum(context.getRuntime(), counter[0]+1);
1404
+ return RubyFixnum.newFixnum(context.runtime, counter[0]+1);
1508
1405
  }
1509
1406
 
1510
1407
  private boolean count(Node node, int[] counter) {
@@ -1526,27 +1423,25 @@ public class XmlNode extends RubyObject {
1526
1423
  @JRubyMethod
1527
1424
  public IRubyObject next_element(ThreadContext context) {
1528
1425
  Node nextNode = node.getNextSibling();
1529
- Ruby ruby = context.getRuntime();
1530
- if (nextNode == null) return ruby.getNil();
1426
+ if (nextNode == null) return context.nil;
1531
1427
  if (nextNode instanceof Element) {
1532
- return getCachedNodeOrCreate(context.getRuntime(), nextNode);
1428
+ return getCachedNodeOrCreate(context.runtime, nextNode);
1533
1429
  }
1534
1430
  Node deeper = nextNode.getNextSibling();
1535
- if (deeper == null) return ruby.getNil();
1536
- return getCachedNodeOrCreate(context.getRuntime(), deeper);
1431
+ if (deeper == null) return context.nil;
1432
+ return getCachedNodeOrCreate(context.runtime, deeper);
1537
1433
  }
1538
1434
 
1539
1435
  @JRubyMethod
1540
1436
  public IRubyObject previous_element(ThreadContext context) {
1541
1437
  Node prevNode = node.getPreviousSibling();
1542
- Ruby ruby = context.getRuntime();
1543
- if (prevNode == null) return ruby.getNil();
1438
+ if (prevNode == null) return context.nil;
1544
1439
  if (prevNode instanceof Element) {
1545
- return getCachedNodeOrCreate(context.getRuntime(), prevNode);
1440
+ return getCachedNodeOrCreate(context.runtime, prevNode);
1546
1441
  }
1547
1442
  Node shallower = prevNode.getPreviousSibling();
1548
- if (shallower == null) return ruby.getNil();
1549
- return getCachedNodeOrCreate(context.getRuntime(), shallower);
1443
+ if (shallower == null) return context.nil;
1444
+ return getCachedNodeOrCreate(context.runtime, shallower);
1550
1445
  }
1551
1446
 
1552
1447
  protected enum AdoptScheme {
@@ -1557,13 +1452,11 @@ public class XmlNode extends RubyObject {
1557
1452
  * Adopt XmlNode <code>other</code> into the document of
1558
1453
  * <code>this</code> using the specified scheme.
1559
1454
  */
1560
- protected IRubyObject adoptAs(ThreadContext context, AdoptScheme scheme,
1561
- IRubyObject other_) {
1562
- XmlNode other = asXmlNode(context, other_);
1455
+ protected IRubyObject adoptAs(ThreadContext context, AdoptScheme scheme, IRubyObject other_) {
1456
+ final XmlNode other = asXmlNode(context, other_);
1563
1457
  // this.doc might be null since this node can be empty node.
1564
- if (this.doc != null) {
1565
- other.setDocument(context, this.doc);
1566
- }
1458
+ if (doc != null) other.setDocument(context, doc);
1459
+
1567
1460
  IRubyObject nodeOrTags = other;
1568
1461
  Node thisNode = node;
1569
1462
  Node otherNode = other.node;
@@ -1572,18 +1465,18 @@ public class XmlNode extends RubyObject {
1572
1465
  Document prev = otherNode.getOwnerDocument();
1573
1466
  Document doc = thisNode.getOwnerDocument();
1574
1467
  if (doc == null && thisNode instanceof Document) {
1575
- // we are adding the new node to a new empty document
1576
- doc = (Document) thisNode;
1468
+ // we are adding the new node to a new empty document
1469
+ doc = (Document) thisNode;
1577
1470
  }
1578
1471
  clearXpathContext(prev);
1579
1472
  clearXpathContext(doc);
1580
1473
  if (doc != null && doc != otherNode.getOwnerDocument()) {
1581
1474
  Node ret = doc.adoptNode(otherNode);
1582
- // FIXME: this is really a hack, see documentation of fixUserData() for more details.
1583
- fixUserData(prev, ret);
1584
1475
  if (ret == null) {
1585
- throw context.getRuntime().newRuntimeError("Failed to take ownership of node");
1476
+ throw context.runtime.newRuntimeError("Failed to take ownership of node");
1586
1477
  }
1478
+ // FIXME: this is really a hack, see documentation of fixUserData() for more details.
1479
+ fixUserData(prev, ret);
1587
1480
  otherNode = ret;
1588
1481
  }
1589
1482
 
@@ -1591,11 +1484,11 @@ public class XmlNode extends RubyObject {
1591
1484
 
1592
1485
  switch (scheme) {
1593
1486
  case CHILD:
1594
- Node[] children = adoptAsChild(context, thisNode, otherNode);
1487
+ Node[] children = adoptAsChild(thisNode, otherNode);
1595
1488
  if (children.length == 1 && otherNode == children[0]) {
1596
1489
  break;
1597
1490
  } else {
1598
- nodeOrTags = nodeArrayToRubyArray(context.getRuntime(), children);
1491
+ nodeOrTags = nodeArrayToRubyArray(context.runtime, children);
1599
1492
  }
1600
1493
  break;
1601
1494
  case PREV_SIBLING:
@@ -1609,7 +1502,7 @@ public class XmlNode extends RubyObject {
1609
1502
  break;
1610
1503
  }
1611
1504
  } catch (Exception e) {
1612
- throw context.getRuntime().newRuntimeError(e.toString());
1505
+ throw context.runtime.newRuntimeError(e.toString());
1613
1506
  }
1614
1507
 
1615
1508
  if (otherNode.getNodeType() == Node.TEXT_NODE) {
@@ -1630,42 +1523,38 @@ public class XmlNode extends RubyObject {
1630
1523
  * It looks like CoreDocumentImpl.adoptNode() doesn't copy
1631
1524
  * the user data associated with child nodes (recursively).
1632
1525
  */
1633
- private void fixUserData(Document previous, Node ret) {
1634
- String key = NokogiriHelpers.ENCODED_STRING;
1635
- for (Node child = ret.getFirstChild(); child != null; child = child.getNextSibling()) {
1636
- CoreDocumentImpl previousDocument = (CoreDocumentImpl) previous;
1637
- child.setUserData(key, previousDocument.getUserData(child, key), null);
1638
- fixUserData(previous, child);
1639
- }
1526
+ private static void fixUserData(Document previous, Node ret) {
1527
+ final String key = NokogiriHelpers.ENCODED_STRING;
1528
+ for (Node child = ret.getFirstChild(); child != null; child = child.getNextSibling()) {
1529
+ CoreDocumentImpl previousDocument = (CoreDocumentImpl) previous;
1530
+ child.setUserData(key, previousDocument.getUserData(child, key), null);
1531
+ fixUserData(previous, child);
1532
+ }
1640
1533
  }
1641
1534
 
1642
- protected Node[] adoptAsChild(ThreadContext context, Node parent,
1643
- Node otherNode) {
1535
+ private Node[] adoptAsChild(final Node parent, Node otherNode) {
1644
1536
  /*
1645
- * This is a bit of a hack. C-Nokogiri allows adding a bare
1646
- * text node as the root element. Java (and XML spec?) does
1647
- * not. So we wrap the text node in an element.
1537
+ * This is a bit of a hack. C-Nokogiri allows adding a bare text node as the root element.
1538
+ * Java (and XML spec?) does not. So we wrap the text node in an element.
1648
1539
  */
1649
1540
  if (parent.getNodeType() == Node.DOCUMENT_NODE && otherNode.getNodeType() == Node.TEXT_NODE) {
1650
- Element e = (Element) parent.getFirstChild();
1651
- if (e == null || !e.getNodeName().equals(TEXT_WRAPPER_NAME)) {
1652
- e = ((Document)parent).createElement(TEXT_WRAPPER_NAME);
1653
- adoptAsChild(context, parent, e);
1654
- }
1655
- e.appendChild(otherNode);
1656
- otherNode = e;
1541
+ Element e = (Element) parent.getFirstChild();
1542
+ if (e == null || !e.getNodeName().equals(TEXT_WRAPPER_NAME)) {
1543
+ e = ((Document) parent).createElement(TEXT_WRAPPER_NAME);
1544
+ adoptAsChild(parent, e);
1545
+ }
1546
+ e.appendChild(otherNode);
1547
+ otherNode = e;
1657
1548
  } else {
1658
- addNamespaceURIIfNeeded(otherNode);
1659
- parent.appendChild(otherNode);
1549
+ addNamespaceURIIfNeeded(otherNode);
1550
+ parent.appendChild(otherNode);
1660
1551
  }
1661
- Node[] nodes = new Node[1];
1662
- nodes[0] = otherNode;
1663
- return nodes;
1552
+ return new Node[] { otherNode };
1664
1553
  }
1665
1554
 
1666
1555
  private void addNamespaceURIIfNeeded(Node child) {
1667
- if (this instanceof XmlDocumentFragment && ((XmlDocumentFragment)this).getFragmentContext() != null) {
1668
- XmlElement fragmentContext = ((XmlDocumentFragment)this).getFragmentContext();
1556
+ if (this instanceof XmlDocumentFragment && ((XmlDocumentFragment) this).getFragmentContext() != null) {
1557
+ XmlElement fragmentContext = ((XmlDocumentFragment) this).getFragmentContext();
1669
1558
  String namespace_uri = fragmentContext.node.getNamespaceURI();
1670
1559
  if (namespace_uri != null && namespace_uri.length() > 0) {
1671
1560
  NokogiriHelpers.renameNode(child, namespace_uri, child.getNodeName());
@@ -1722,7 +1611,7 @@ public class XmlNode extends RubyObject {
1722
1611
  parentNode.replaceChild(otherNode, thisNode);
1723
1612
  } catch (Exception e) {
1724
1613
  String prefix = "could not replace child: ";
1725
- throw context.getRuntime().newRuntimeError(prefix + e.toString());
1614
+ throw context.runtime.newRuntimeError(prefix + e.toString());
1726
1615
  }
1727
1616
  }
1728
1617
 
@@ -1784,4 +1673,14 @@ public class XmlNode extends RubyObject {
1784
1673
  clearXpathContext(getNode());
1785
1674
  return context.nil ;
1786
1675
  }
1676
+
1677
+ @SuppressWarnings("unchecked")
1678
+ @Override
1679
+ public Object toJava(final Class target) {
1680
+ if (target == Object.class || Node.class.isAssignableFrom(target)) {
1681
+ return getNode();
1682
+ }
1683
+ return super.toJava(target);
1684
+ }
1685
+
1787
1686
  }