nokogiri 1.6.7.2-java → 1.6.8-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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.cross_rubies +2 -0
  3. data/.travis.yml +19 -9
  4. data/CHANGELOG.rdoc +73 -5
  5. data/CONTRIBUTING.md +42 -0
  6. data/Gemfile +10 -9
  7. data/LICENSE.txt +1 -1
  8. data/Manifest.txt +7 -2
  9. data/README.md +23 -27
  10. data/ROADMAP.md +11 -1
  11. data/Rakefile +36 -17
  12. data/bin/nokogiri +2 -2
  13. data/dependencies.yml +29 -4
  14. data/ext/java/nokogiri/HtmlElementDescription.java +5 -2
  15. data/ext/java/nokogiri/NokogiriService.java +19 -0
  16. data/ext/java/nokogiri/XmlAttr.java +3 -1
  17. data/ext/java/nokogiri/XmlDocumentFragment.java +0 -14
  18. data/ext/java/nokogiri/XmlNode.java +106 -63
  19. data/ext/java/nokogiri/XmlXpathContext.java +12 -12
  20. data/ext/java/nokogiri/XsltStylesheet.java +11 -4
  21. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +8 -1
  22. data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +1 -2
  23. data/ext/java/nokogiri/internals/NokogiriHelpers.java +7 -7
  24. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +1 -1
  25. data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +0 -1
  26. data/ext/java/nokogiri/internals/NokogiriXsltErrorListener.java +3 -3
  27. data/ext/java/nokogiri/internals/ParserContext.java +4 -0
  28. data/ext/java/nokogiri/internals/SaveContextVisitor.java +18 -13
  29. data/ext/nokogiri/extconf.rb +163 -79
  30. data/ext/nokogiri/html_document.c +6 -6
  31. data/ext/nokogiri/html_element_description.c +1 -1
  32. data/ext/nokogiri/html_entity_lookup.c +1 -1
  33. data/ext/nokogiri/html_sax_parser_context.c +4 -4
  34. data/ext/nokogiri/html_sax_push_parser.c +2 -2
  35. data/ext/nokogiri/nokogiri.c +0 -7
  36. data/ext/nokogiri/nokogiri.h +1 -34
  37. data/ext/nokogiri/xml_attr.c +2 -2
  38. data/ext/nokogiri/xml_comment.c +1 -1
  39. data/ext/nokogiri/xml_document.c +20 -22
  40. data/ext/nokogiri/xml_encoding_handler.c +3 -3
  41. data/ext/nokogiri/xml_entity_reference.c +1 -1
  42. data/ext/nokogiri/xml_namespace.c +56 -17
  43. data/ext/nokogiri/xml_node.c +73 -67
  44. data/ext/nokogiri/xml_node_set.c +164 -146
  45. data/ext/nokogiri/xml_node_set.h +3 -4
  46. data/ext/nokogiri/xml_processing_instruction.c +2 -2
  47. data/ext/nokogiri/xml_reader.c +5 -18
  48. data/ext/nokogiri/xml_sax_parser.c +9 -12
  49. data/ext/nokogiri/xml_sax_parser_context.c +1 -1
  50. data/ext/nokogiri/xml_sax_push_parser.c +1 -1
  51. data/ext/nokogiri/xml_schema.c +1 -1
  52. data/ext/nokogiri/xml_syntax_error.c +0 -4
  53. data/ext/nokogiri/xml_syntax_error.h +0 -1
  54. data/ext/nokogiri/xml_text.c +1 -1
  55. data/ext/nokogiri/xml_xpath_context.c +15 -24
  56. data/ext/nokogiri/xslt_stylesheet.c +6 -6
  57. data/lib/nekohtml.jar +0 -0
  58. data/lib/nokogiri.rb +14 -7
  59. data/lib/nokogiri/css/parser.rb +8 -2
  60. data/lib/nokogiri/css/parser.y +7 -2
  61. data/lib/nokogiri/html/document.rb +4 -2
  62. data/lib/nokogiri/nokogiri.jar +0 -0
  63. data/lib/nokogiri/version.rb +1 -1
  64. data/lib/nokogiri/xml/document.rb +7 -1
  65. data/lib/nokogiri/xml/dtd.rb +4 -4
  66. data/lib/nokogiri/xml/node.rb +6 -10
  67. data/lib/nokogiri/xml/node_set.rb +3 -3
  68. data/lib/nokogiri/xml/parse_options.rb +22 -0
  69. data/lib/serializer.jar +0 -0
  70. data/lib/xalan.jar +0 -0
  71. data/lib/xercesImpl.jar +0 -0
  72. data/lib/xml-apis.jar +0 -0
  73. data/tasks/test.rb +5 -0
  74. data/test/css/test_parser.rb +7 -1
  75. data/test/files/GH_1042.html +18 -0
  76. data/test/files/namespace_pressure_test.xml +1684 -0
  77. data/test/files/tlm.html +2 -1
  78. data/test/helper.rb +4 -0
  79. data/test/html/sax/test_parser.rb +2 -2
  80. data/test/html/test_document.rb +47 -11
  81. data/test/html/test_document_encoding.rb +55 -58
  82. data/test/html/test_document_fragment.rb +27 -23
  83. data/test/html/test_node.rb +16 -0
  84. data/test/html/test_node_encoding.rb +71 -13
  85. data/test/namespaces/test_namespaces_in_parsed_doc.rb +14 -0
  86. data/test/test_css_cache.rb +1 -1
  87. data/test/test_encoding_handler.rb +2 -0
  88. data/test/test_xslt_transforms.rb +38 -3
  89. data/test/xml/sax/test_parser.rb +54 -53
  90. data/test/xml/test_document.rb +7 -2
  91. data/test/xml/test_document_encoding.rb +19 -16
  92. data/test/xml/test_document_fragment.rb +12 -0
  93. data/test/xml/test_dtd_encoding.rb +0 -2
  94. data/test/xml/test_namespace.rb +2 -2
  95. data/test/xml/test_node.rb +15 -4
  96. data/test/xml/test_node_attributes.rb +6 -0
  97. data/test/xml/test_node_encoding.rb +49 -87
  98. data/test/xml/test_node_reparenting.rb +193 -18
  99. data/test/xml/test_node_set.rb +1 -1
  100. data/test/xml/test_reader.rb +589 -0
  101. data/test/xml/test_reader_encoding.rb +100 -102
  102. data/test/xml/test_unparented_node.rb +14 -1
  103. data/test/xslt/test_exception_handling.rb +1 -1
  104. data/test_all +47 -33
  105. metadata +38 -36
  106. data/CHANGELOG.ja.rdoc +0 -1057
  107. data/test/test_reader.rb +0 -558
@@ -41,9 +41,9 @@ opts = OptionParser.new do |opts|
41
41
  opts.define_head "Usage: nokogiri <uri|path> [options]"
42
42
  opts.separator ""
43
43
  opts.separator "Examples:"
44
- opts.separator " nokogiri http://www.ruby-lang.org/"
44
+ opts.separator " nokogiri https://www.ruby-lang.org/"
45
45
  opts.separator " nokogiri ./public/index.html"
46
- opts.separator " curl -s http://nokogiri.org | nokogiri -e'p $_.css(\"h1\").length'"
46
+ opts.separator " curl -s http://www.nokogiri.org | nokogiri -e'p $_.css(\"h1\").length'"
47
47
  opts.separator ""
48
48
  opts.separator "Options:"
49
49
 
@@ -1,4 +1,29 @@
1
- libxml2: "2.9.2"
2
- libxslt: "1.1.28"
3
- zlib: "1.2.8"
4
- libiconv: "1.14"
1
+ libxml2:
2
+ version: "2.9.4"
3
+ md5: "ae249165c173b1ff386ee8ad676815f5" # manually confirmed via `gpg --verify`
4
+ # gpg: Signature made Mon 23 May 2016 04:02:13 AM EDT using DSA key ID DE95BC1F
5
+ # gpg: Good signature from "Daniel Veillard (Red Hat work email) <veillard@redhat.com>"
6
+ # gpg: aka "Daniel Veillard <Daniel.Veillard@w3.org>"
7
+ # gpg: WARNING: This key is not certified with a trusted signature!
8
+ # gpg: There is no indication that the signature belongs to the owner.
9
+ # Primary key fingerprint: C744 15BA 7C9C 7F78 F02E 1DC3 4606 B8A5 DE95 BC1F
10
+
11
+ libxslt:
12
+ version: "1.1.29"
13
+ md5: "a129d3c44c022de3b9dcf6d6f288d72e"
14
+ # gpg: Signature made Mon 23 May 2016 09:58:52 PM EDT using DSA key ID DE95BC1F
15
+ # gpg: Good signature from "Daniel Veillard (Red Hat work email) <veillard@redhat.com>"
16
+ # gpg: aka "Daniel Veillard <Daniel.Veillard@w3.org>"
17
+ # gpg: WARNING: This key is not certified with a trusted signature!
18
+ # gpg: There is no indication that the signature belongs to the owner.
19
+ # Primary key fingerprint: C744 15BA 7C9C 7F78 F02E 1DC3 4606 B8A5 DE95 BC1F
20
+
21
+ zlib:
22
+ version: "1.2.8"
23
+ md5: "44d667c142d7cda120332623eab69f40"
24
+
25
+ libiconv:
26
+ version: "1.14"
27
+ md5: "e34509b1623cec449dfeb73d7ce9c6c6"
28
+ # gpg: Signature made Sun 07 Aug 2011 01:58:18 PM EDT using DSA key ID F059B1D1
29
+ # gpg: BAD signature from "Bruno Haible (Open Source Development) <bruno@clisp.org>"
@@ -105,9 +105,12 @@ public class HtmlElementDescription extends RubyObject {
105
105
  public static IRubyObject get(ThreadContext context,
106
106
  IRubyObject klazz, IRubyObject name) {
107
107
 
108
- HTMLElements.Element elem = HTMLElements.getElement(name.toString());
108
+ // nekohtml will return an element even for invalid names, see
109
+ // http://sourceforge.net/p/nekohtml/code/HEAD/tree/trunk/src/org/cyberneko/html/HTMLElements.java#l514
110
+ // which breaks `test_fetch_nonexistent'
111
+ HTMLElements.Element elem = HTMLElements.getElement(name.asJavaString(), HTMLElements.NO_SUCH_ELEMENT);
109
112
  if (elem == HTMLElements.NO_SUCH_ELEMENT)
110
- return context.getRuntime().getNil();
113
+ return context.nil;
111
114
 
112
115
  HtmlElementDescription desc =
113
116
  new HtmlElementDescription(context.getRuntime(), (RubyClass)klazz);
@@ -36,6 +36,7 @@ import java.util.Collections;
36
36
  import java.util.HashMap;
37
37
  import java.util.Map;
38
38
 
39
+ import org.cyberneko.html.HTMLElements;
39
40
  import org.jruby.Ruby;
40
41
  import org.jruby.RubyArray;
41
42
  import org.jruby.RubyClass;
@@ -53,6 +54,24 @@ import org.jruby.runtime.load.BasicLibraryService;
53
54
  * @author Yoko Harada <yokolet@gmail.com>
54
55
  */
55
56
  public class NokogiriService implements BasicLibraryService {
57
+
58
+ // nekohtml from version 1.9.13 they autocomplete tbody around
59
+ // tr tags of a table - http://sourceforge.net/p/nekohtml/code/241/
60
+ // this monkey patch undoes this autocompletion
61
+ static class MonkeyPatchHTMLElements extends HTMLElements {
62
+ static void patchIt() {
63
+ Element[] array = ELEMENTS_ARRAY['T'-'A'];
64
+ for(int i = 0; i < array.length; i++) {
65
+ if (array[i].name.equals("TR")) {
66
+ array[i] = new Element(TR, "TR", Element.BLOCK, TABLE, new short[]{TD,TH,TR,COLGROUP,DIV});
67
+ }
68
+ }
69
+ }
70
+ }
71
+ static {
72
+ MonkeyPatchHTMLElements.patchIt();
73
+ }
74
+
56
75
  public static final String nokogiriClassCacheGvarName = "$NOKOGIRI_CLASS_CACHE";
57
76
 
58
77
  public boolean basicLoad(Ruby ruby) {
@@ -164,7 +164,9 @@ public class XmlAttr extends XmlNode{
164
164
  protected IRubyObject getNodeName(ThreadContext context) {
165
165
  if (name != null) return name;
166
166
  String attrName = ((Attr)node).getName();
167
- if (!(doc instanceof HtmlDocument)) attrName = NokogiriHelpers.getLocalPart(attrName);
167
+ if (!(doc instanceof HtmlDocument) && node.getNamespaceURI() != null) {
168
+ attrName = NokogiriHelpers.getLocalPart(attrName);
169
+ }
168
170
  return attrName == null ? context.getRuntime().getNil() : RubyString.newString(context.getRuntime(), attrName);
169
171
  }
170
172
 
@@ -54,7 +54,6 @@ import org.jruby.javasupport.util.RuntimeHelpers;
54
54
  import org.jruby.runtime.ThreadContext;
55
55
  import org.jruby.runtime.builtin.IRubyObject;
56
56
  import org.w3c.dom.Attr;
57
- import org.w3c.dom.Document;
58
57
  import org.w3c.dom.NamedNodeMap;
59
58
 
60
59
  /**
@@ -90,7 +89,6 @@ public class XmlDocumentFragment extends XmlNode {
90
89
 
91
90
  // make wellformed fragment, ignore invalid namespace, or add appropriate namespace to parse
92
91
  if (args.length > 1 && args[1] instanceof RubyString) {
93
- args[1] = trim(context, doc, (RubyString)args[1]);
94
92
  if (XmlDocumentFragment.isTag((RubyString)args[1])) {
95
93
  args[1] = RubyString.newString(context.getRuntime(), addNamespaceDeclIfNeeded(doc, rubyStringToString(args[1])));
96
94
  }
@@ -107,18 +105,6 @@ public class XmlDocumentFragment extends XmlNode {
107
105
  RuntimeHelpers.invoke(context, fragment, "initialize", args);
108
106
  return fragment;
109
107
  }
110
-
111
- private static IRubyObject trim(ThreadContext context, XmlDocument xmlDocument, RubyString str) {
112
- // checks whether schema is given. if exists, allows whitespace processing to a parser
113
- Document document = (Document)xmlDocument.node;
114
- if (document.getDoctype() != null) return str;
115
- // strips trailing \n off forcefully
116
- // not to return new object in case of no chomp needed, chomp! is used here.
117
- IRubyObject result;
118
- if (context.getRuntime().is1_9()) result = str.chomp_bang19(context);
119
- else result = str.chomp_bang(context);
120
- return result.isNil() ? str : result;
121
- }
122
108
 
123
109
  private static boolean isTag(RubyString ruby_string) {
124
110
  String str = rubyStringToString(ruby_string);
@@ -333,15 +333,11 @@ public class XmlNode extends RubyObject {
333
333
  Element element = null;
334
334
  String node_name = rubyStringToString(name);
335
335
  String prefix = NokogiriHelpers.getPrefix(node_name);
336
- if (prefix == null) {
337
- element = document.createElement(node_name);
338
- } else {
339
- String namespace_uri = null;
340
- if (document.getDocumentElement() != null) {
341
- namespace_uri = document.getDocumentElement().lookupNamespaceURI(prefix);
342
- }
343
- element = document.createElementNS(namespace_uri, node_name);
336
+ String namespace_uri = null;
337
+ if (document.getDocumentElement() != null) {
338
+ namespace_uri = document.getDocumentElement().lookupNamespaceURI(prefix);
344
339
  }
340
+ element = document.createElementNS(namespace_uri, node_name);
345
341
  setNode(context, element);
346
342
  }
347
343
 
@@ -454,57 +450,77 @@ public class XmlNode extends RubyObject {
454
450
  public void post_add_child(ThreadContext context, XmlNode current, XmlNode child) {
455
451
  }
456
452
 
453
+ /**
454
+ * This method should be called after a node has been adopted in a new
455
+ * document. This method will ensure that the node is renamed with the
456
+ * appriopriate NS uri. First the prefix of the node is extracted, then is
457
+ * used to lookup the namespace uri in the new document starting at the
458
+ * current node and traversing the ancestors. If the namespace uri wasn't
459
+ * empty (or null) all children and the node has attributes and/or children
460
+ * then the algorithm is recursively applied to the children.
461
+ */
457
462
  public void relink_namespace(ThreadContext context) {
458
- if (node instanceof Element) {
459
- clearCachedNode(node);
460
- Element e = (Element) node;
461
- String prefix = e.getPrefix();
462
- String currentNS = e.getNamespaceURI();
463
- if (prefix == null && currentNS == null) {
464
- prefix = NokogiriHelpers.getPrefix(e.getNodeName());
465
- } else if (currentNS != null) {
466
- prefix = e.lookupPrefix(currentNS);
467
- }
468
- e.getOwnerDocument().setStrictErrorChecking(false);
469
- String nsURI = e.lookupNamespaceURI(prefix);
470
- this.node = NokogiriHelpers.renameNode(e, nsURI, e.getNodeName());
471
-
472
- if (e.hasAttributes()) {
473
- NamedNodeMap attrs = e.getAttributes();
474
-
475
- for (int i = 0; i < attrs.getLength(); i++) {
476
- Attr attr = (Attr) attrs.item(i);
477
- String nsUri = "";
478
- String attrPrefix = attr.getPrefix();
479
- if (attrPrefix == null) {
480
- attrPrefix = NokogiriHelpers.getPrefix(attr.getNodeName());
481
- }
482
- String nodeName = attr.getNodeName();
483
- if ("xml".equals(attrPrefix)) {
484
- nsUri = "http://www.w3.org/XML/1998/namespace";
485
- } else if ("xmlns".equals(attrPrefix) || nodeName.equals("xmlns")) {
486
- nsUri = "http://www.w3.org/2000/xmlns/";
487
- } else {
488
- nsUri = attr.lookupNamespaceURI(attrPrefix);
489
- }
463
+ if (!(node instanceof Element)) {
464
+ return;
465
+ }
490
466
 
491
- if (nsUri == e.getNamespaceURI()) {
492
- nsUri = null;
493
- }
467
+ // TODO: this feels kind of weird, why are we clearing the XmlNode
468
+ // cache here !!!
469
+ clearCachedNode(node);
470
+ Element e = (Element) node;
494
471
 
495
- if (!(nsUri == null || "".equals(nsUri) || "http://www.w3.org/XML/1998/namespace".equals(nsUri))) {
496
- XmlNamespace.createFromAttr(context.getRuntime(), attr);
497
- }
498
- clearCachedNode(attr);
499
- NokogiriHelpers.renameNode(attr, nsUri, nodeName);
472
+ // disable error checking to prevent lines like the following
473
+ // from throwing a `NAMESPACE_ERR' exception:
474
+ // Nokogiri::XML::DocumentFragment.parse("<o:div>a</o:div>")
475
+ // since the `o' prefix isn't defined anywhere.
476
+ e.getOwnerDocument().setStrictErrorChecking(false);
477
+
478
+ String prefix = e.getPrefix();
479
+ String nsURI = e.lookupNamespaceURI(prefix);
480
+ this.node = NokogiriHelpers.renameNode(e, nsURI, e.getNodeName());
481
+
482
+ if (nsURI == null || nsURI == "") {
483
+ return;
484
+ }
485
+
486
+ if (e.hasAttributes()) {
487
+ NamedNodeMap attrs = e.getAttributes();
488
+
489
+ for (int i = 0; i < attrs.getLength(); i++) {
490
+ Attr attr = (Attr) attrs.item(i);
491
+ String nsUri = "";
492
+ String attrPrefix = attr.getPrefix();
493
+ if (attrPrefix == null) {
494
+ attrPrefix = NokogiriHelpers.getPrefix(attr.getNodeName());
495
+ }
496
+ String nodeName = attr.getNodeName();
497
+ if ("xml".equals(attrPrefix)) {
498
+ nsUri = "http://www.w3.org/XML/1998/namespace";
499
+ } else if ("xmlns".equals(attrPrefix) || nodeName.equals("xmlns")) {
500
+ nsUri = "http://www.w3.org/2000/xmlns/";
501
+ } else {
502
+ nsUri = attr.lookupNamespaceURI(attrPrefix);
500
503
  }
501
- }
502
504
 
503
- if (this.node.hasChildNodes()) {
504
- XmlNodeSet nodeSet = (XmlNodeSet)(children(context));
505
- nodeSet.relink_namespace(context);
505
+ if (nsUri == e.getNamespaceURI()) {
506
+ nsUri = null;
507
+ }
508
+
509
+ if (!(nsUri == null || "".equals(nsUri) || "http://www.w3.org/XML/1998/namespace".equals(nsUri))) {
510
+ // Create a new namespace object and add it to the document
511
+ // namespace cache.
512
+ // TODO: why do we need the namespace cache ?
513
+ XmlNamespace.createFromAttr(context.getRuntime(), attr);
514
+ }
515
+ clearCachedNode(attr);
516
+ NokogiriHelpers.renameNode(attr, nsUri, nodeName);
506
517
  }
507
518
  }
519
+
520
+ if (this.node.hasChildNodes()) {
521
+ XmlNodeSet nodeSet = (XmlNodeSet)(children(context));
522
+ nodeSet.relink_namespace(context);
523
+ }
508
524
  }
509
525
 
510
526
  // Users might extend XmlNode. This method works for such a case.
@@ -605,6 +621,7 @@ public class XmlNode extends RubyObject {
605
621
 
606
622
  NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCacheFormNode(node);
607
623
  XmlNamespace cachedNamespace = nsCache.get(prefixString, hrefString);
624
+
608
625
  if (cachedNamespace != null) return cachedNamespace;
609
626
 
610
627
  Node namespaceOwner;
@@ -615,12 +632,14 @@ public class XmlNode extends RubyObject {
615
632
  final String uri = "http://www.w3.org/2000/xmlns/";
616
633
  String qName =
617
634
  prefix.isNil() ? "xmlns" : "xmlns:" + prefixString;
635
+
618
636
  element.setAttributeNS(uri, qName, hrefString);
619
637
  }
620
638
  else if (node.getNodeType() == Node.ATTRIBUTE_NODE) namespaceOwner = ((Attr)node).getOwnerElement();
621
639
  else namespaceOwner = node.getParentNode();
622
640
  XmlNamespace ns = XmlNamespace.createFromPrefixAndHref(namespaceOwner, prefix, href);
623
641
  if (node != namespaceOwner) {
642
+
624
643
  this.node = NokogiriHelpers.renameNode(node, ns.getHref(), ns.getPrefix() + ":" + node.getLocalName());
625
644
  }
626
645
  updateNodeNamespaceIfNecessary(context, ns);
@@ -806,6 +825,13 @@ public class XmlNode extends RubyObject {
806
825
  }
807
826
 
808
827
  ctx.setInputSource(istream);
828
+ // TODO: for some reason, document.getEncoding() can be null or nil (don't know why)
829
+ // run `test_parse_with_unparented_html_text_context_node' few times to see this happen
830
+ if (document instanceof HtmlDocument && !(document.getEncoding() == null || document.getEncoding().isNil())) {
831
+ HtmlDomParserContext htmlCtx= (HtmlDomParserContext) ctx;
832
+ htmlCtx.setEncoding(document.getEncoding().asJavaString());
833
+ }
834
+
809
835
  XmlDocument doc = ctx.parse(context, klass, runtime.getNil());
810
836
 
811
837
  RubyArray documentErrors = getErrorArray(document);
@@ -904,6 +930,10 @@ public class XmlNode extends RubyObject {
904
930
  return doc;
905
931
  }
906
932
 
933
+ public IRubyObject dup() {
934
+ return this.dup_implementation(getMetaClass().getClassRuntime(), true);
935
+ }
936
+
907
937
  @JRubyMethod
908
938
  public IRubyObject dup(ThreadContext context) {
909
939
  return this.dup_implementation(context, true);
@@ -917,13 +947,17 @@ public class XmlNode extends RubyObject {
917
947
  }
918
948
 
919
949
  protected IRubyObject dup_implementation(ThreadContext context, boolean deep) {
950
+ return dup_implementation(context.getRuntime(), deep);
951
+ }
952
+
953
+ protected IRubyObject dup_implementation(Ruby runtime, boolean deep) {
920
954
  XmlNode clone;
921
955
  try {
922
956
  clone = (XmlNode) clone();
923
957
  } catch (CloneNotSupportedException e) {
924
- throw context.getRuntime().newRuntimeError(e.toString());
958
+ throw runtime.newRuntimeError(e.toString());
925
959
  }
926
- if (node == null) throw context.getRuntime().newRuntimeError("FFFFFFFFFUUUUUUU");
960
+ if (node == null) throw runtime.newRuntimeError("FFFFFFFFFUUUUUUU");
927
961
  Node newNode = node.cloneNode(deep);
928
962
  clone.node = newNode;
929
963
  return clone;
@@ -1074,12 +1108,24 @@ public class XmlNode extends RubyObject {
1074
1108
 
1075
1109
  @JRubyMethod
1076
1110
  public IRubyObject namespace(ThreadContext context) {
1077
- if (doc instanceof HtmlDocument) return context.getRuntime().getNil();
1111
+ Ruby runtime = context.getRuntime();
1112
+ if (doc instanceof HtmlDocument) return runtime.getNil();
1078
1113
  NokogiriNamespaceCache nsCache = NokogiriHelpers.getNamespaceCacheFormNode(node);
1114
+ String namespaceURI = node.getNamespaceURI();
1115
+ if (namespaceURI == null || namespaceURI == "") {
1116
+ return runtime.getNil();
1117
+ }
1118
+
1079
1119
  String prefix = node.getPrefix();
1080
- XmlNamespace namespace = nsCache.get(prefix == null ? "" : prefix, node.getNamespaceURI());
1120
+ XmlNamespace namespace = nsCache.get(prefix == null ? "" : prefix, namespaceURI);
1081
1121
  if (namespace == null || namespace.isEmpty()) {
1082
- return context.getRuntime().getNil();
1122
+ // if it's not in the cache, create an unowned, uncached namespace and
1123
+ // return that. XmlReader can't insert namespaces into the cache, so
1124
+ // this is necessary for XmlReader to work correctly.
1125
+ namespace = new XmlNamespace(runtime, getNokogiriClass(runtime, "Nokogiri::XML::Namespace"));
1126
+ IRubyObject rubyPrefix = NokogiriHelpers.stringOrNil(runtime, prefix);
1127
+ IRubyObject rubyUri = NokogiriHelpers.stringOrNil(runtime, namespaceURI);
1128
+ namespace.init(null, rubyPrefix, rubyUri, doc);
1083
1129
  }
1084
1130
 
1085
1131
  return namespace;
@@ -1296,7 +1342,7 @@ public class XmlNode extends RubyObject {
1296
1342
  } else if (prefix.equals("xmlns")) {
1297
1343
  uri = "http://www.w3.org/2000/xmlns/";
1298
1344
  } else {
1299
- uri = findNamespaceHref(context, prefix);
1345
+ uri = node.lookupNamespaceURI(prefix);
1300
1346
  }
1301
1347
  }
1302
1348
 
@@ -1386,13 +1432,10 @@ public class XmlNode extends RubyObject {
1386
1432
 
1387
1433
  @JRubyMethod(name = {"unlink", "remove"})
1388
1434
  public IRubyObject unlink(ThreadContext context) {
1389
- if(node.getParentNode() == null) {
1390
- throw context.getRuntime().newRuntimeError("TYPE: " + node.getNodeType()+ " PARENT NULL");
1391
- } else {
1435
+ if (node.getParentNode() != null) {
1392
1436
  clearXpathContext(node.getParentNode());
1393
1437
  node.getParentNode().removeChild(node);
1394
1438
  }
1395
-
1396
1439
  return this;
1397
1440
  }
1398
1441
 
@@ -1555,7 +1598,7 @@ public class XmlNode extends RubyObject {
1555
1598
  ((XmlDocument) this).resetNamespaceCache(context);
1556
1599
  }
1557
1600
 
1558
- relink_namespace(context);
1601
+ other.relink_namespace(context);
1559
1602
  // post_add_child(context, this, other);
1560
1603
 
1561
1604
  return nodeOrTags;
@@ -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.
@@ -58,13 +58,13 @@ import org.jruby.runtime.builtin.IRubyObject;
58
58
  import org.w3c.dom.Node;
59
59
  import org.w3c.dom.NodeList;
60
60
 
61
- import com.sun.org.apache.xml.internal.dtm.DTM;
62
- import com.sun.org.apache.xml.internal.utils.PrefixResolver;
63
- import com.sun.org.apache.xpath.internal.XPathContext;
64
- import com.sun.org.apache.xpath.internal.jaxp.JAXPExtensionsProvider;
65
- import com.sun.org.apache.xpath.internal.jaxp.JAXPPrefixResolver;
66
- import com.sun.org.apache.xpath.internal.jaxp.JAXPVariableStack;
67
- import com.sun.org.apache.xpath.internal.objects.XObject;
61
+ import org.apache.xml.dtm.DTM;
62
+ import org.apache.xml.utils.PrefixResolver;
63
+ import org.apache.xpath.XPathContext;
64
+ import org.apache.xpath.jaxp.JAXPExtensionsProvider;
65
+ import org.apache.xpath.jaxp.JAXPPrefixResolver;
66
+ import org.apache.xpath.jaxp.JAXPVariableStack;
67
+ import org.apache.xpath.objects.XObject;
68
68
 
69
69
  /**
70
70
  * Class for Nokogiri::XML::XpathContext
@@ -110,7 +110,7 @@ public class XmlXpathContext extends RubyObject {
110
110
  }
111
111
 
112
112
  private JAXPExtensionsProvider getProviderInstance() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
113
- Class<?> clazz = Class.forName("com.sun.org.apache.xpath.internal.jaxp.JAXPExtensionsProvider");
113
+ Class<?> clazz = Class.forName("org.apache.xpath.jaxp.JAXPExtensionsProvider");
114
114
  Constructor[] constructors = clazz.getDeclaredConstructors();
115
115
  for (int i = 0; i < constructors.length; i++) {
116
116
  Class[] parameterTypes = constructors[i].getParameterTypes();
@@ -184,8 +184,8 @@ public class XmlXpathContext extends RubyObject {
184
184
  Node contextNode = context.node;
185
185
 
186
186
  try {
187
- com.sun.org.apache.xpath.internal.XPath xpathInternal = new com.sun.org.apache.xpath.internal.XPath (expr, null,
188
- prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT );
187
+ org.apache.xpath.XPath xpathInternal = new org.apache.xpath.XPath (expr, null,
188
+ prefixResolver, org.apache.xpath.XPath.SELECT );
189
189
 
190
190
  // We always need to have a ContextNode with Xalan XPath implementation
191
191
  // To allow simple expression evaluation like 1+1 we are setting