nokogiri 1.5.7.rc1-java → 1.5.7.rc2-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.

@@ -71,9 +71,11 @@ import org.jruby.runtime.ThreadContext;
71
71
  import org.jruby.runtime.builtin.IRubyObject;
72
72
  import org.jruby.util.ByteList;
73
73
  import org.w3c.dom.Attr;
74
+ import org.w3c.dom.Document;
74
75
  import org.w3c.dom.NamedNodeMap;
75
76
  import org.w3c.dom.Node;
76
77
  import org.w3c.dom.NodeList;
78
+ import org.w3c.dom.DOMException;
77
79
 
78
80
  /**
79
81
  * A class for various utility methods.
@@ -634,10 +636,11 @@ public class NokogiriHelpers {
634
636
  }
635
637
 
636
638
  public static String newQName(String newPrefix, Node node) {
639
+ String tagName = getLocalPart(node.getNodeName());
637
640
  if(newPrefix == null) {
638
- return node.getLocalName();
641
+ return tagName;
639
642
  } else {
640
- return newPrefix + ":" + node.getLocalName();
643
+ return newPrefix + ":" + tagName;
641
644
  }
642
645
  }
643
646
 
@@ -807,4 +810,16 @@ public class NokogiriHelpers {
807
810
  public static boolean shouldDecode(Node text) {
808
811
  return !shouldEncode(text);
809
812
  }
813
+
814
+ public static Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException {
815
+ Document doc = n.getOwnerDocument();
816
+ XmlDocument xmlDoc = (XmlDocument)getCachedNode(doc);
817
+ NokogiriNamespaceCache nsCache = xmlDoc.getNamespaceCache();
818
+ int oldHash = n.hashCode();
819
+ Node result = doc.renameNode(n, namespaceURI, qualifiedName);
820
+ if (result != n) {
821
+ nsCache.replaceNode(n, result);
822
+ }
823
+ return result;
824
+ }
810
825
  }
@@ -99,7 +99,7 @@ public class NokogiriNamespaceCache {
99
99
  List<XmlNamespace> namespaces = new ArrayList<XmlNamespace>();
100
100
  for (int i=0; i < keys.size(); i++) {
101
101
  CacheEntry entry = cache.get(i);
102
- if (entry.ownerNode == node) {
102
+ if (entry.isOwner(node)) {
103
103
  namespaces.add(entry.namespace);
104
104
  }
105
105
  }
@@ -151,6 +151,15 @@ public class NokogiriNamespaceCache {
151
151
  defaultNamespace = null;
152
152
  }
153
153
 
154
+ public void replaceNode(Node oldNode, Node newNode) {
155
+ for (int i=0; i < keys.size(); i++) {
156
+ CacheEntry entry = cache.get(i);
157
+ if (entry.isOwner(oldNode)) {
158
+ entry.replaceOwner(newNode);
159
+ }
160
+ }
161
+ }
162
+
154
163
  private class CacheEntry {
155
164
  private XmlNamespace namespace;
156
165
  private Node ownerNode;
@@ -159,5 +168,13 @@ public class NokogiriNamespaceCache {
159
168
  this.namespace = namespace;
160
169
  this.ownerNode = ownerNode;
161
170
  }
171
+
172
+ public Boolean isOwner(Node n) {
173
+ return this.ownerNode.isSameNode(n);
174
+ }
175
+
176
+ public void replaceOwner(Node newNode) {
177
+ this.ownerNode = newNode;
178
+ }
162
179
  }
163
180
  }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * (The MIT License)
3
+ *
4
+ * Copyright (c) 2008 - 2012:
5
+ *
6
+ * * {Aaron Patterson}[http://tenderlovemaking.com]
7
+ * * {Mike Dalessio}[http://mike.daless.io]
8
+ * * {Charles Nutter}[http://blog.headius.com]
9
+ * * {Sergio Arbeo}[http://www.serabe.com]
10
+ * * {Patrick Mahoney}[http://polycrystal.org]
11
+ * * {Yoko Harada}[http://yokolet.blogspot.com]
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining
14
+ * a copy of this software and associated documentation files (the
15
+ * 'Software'), to deal in the Software without restriction, including
16
+ * without limitation the rights to use, copy, modify, merge, publish,
17
+ * distribute, sublicense, and/or sell copies of the Software, and to
18
+ * permit persons to whom the Software is furnished to do so, subject to
19
+ * the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be
22
+ * included in all copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ */
32
+
33
+ package nokogiri.internals;
34
+
35
+ import java.io.IOException;
36
+ import java.io.InputStream;
37
+
38
+ /**
39
+ * Delegates all the methods to another InputStream except the
40
+ * close() method, which is ignored. This is used to fix #495.
41
+ *
42
+ * @author John Shahid <jvshahid@gmail.com>
43
+ */
44
+ public class UncloseableInputStream extends InputStream {
45
+ private final InputStream delegate;
46
+
47
+ /**
48
+ * Create a new uncloseable stream.
49
+ *
50
+ * @param delegate The InputStream to which all methods (except close)
51
+ * will be delegated.
52
+ */
53
+ public UncloseableInputStream(InputStream delegate) {
54
+ this.delegate = delegate;
55
+ }
56
+
57
+ @Override
58
+ public int read() throws IOException {
59
+ return delegate.read();
60
+ }
61
+
62
+ @Override
63
+ public int read(byte []b) throws IOException {
64
+ return delegate.read(b);
65
+ }
66
+
67
+ @Override
68
+ public int read(byte []b, int offset, int len) throws IOException {
69
+ return delegate.read(b, offset, len);
70
+ }
71
+
72
+ @Override
73
+ public long skip(long n) throws IOException {
74
+ return delegate.skip(n);
75
+ }
76
+
77
+ @Override
78
+ public int available() throws IOException {
79
+ return delegate.available();
80
+ }
81
+
82
+ @Override
83
+ public void close() {
84
+ // don't forward this to the InputStream we're delegating from
85
+ // we don't want the InputStream of the RubyIO to be closed
86
+ }
87
+
88
+ @Override
89
+ public void mark(int readlimit) {
90
+ delegate.mark(readlimit);
91
+ }
92
+
93
+ @Override
94
+ public void reset() throws IOException {
95
+ delegate.reset();
96
+ }
97
+
98
+ @Override
99
+ public boolean markSupported() {
100
+ return delegate.markSupported();
101
+ }
102
+ }
@@ -157,4 +157,8 @@ void nokogiri_root_nsdef(xmlNsPtr, xmlDocPtr);
157
157
  # endif
158
158
  #endif
159
159
 
160
+ #define XMLNS_PREFIX "xmlns"
161
+ #define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
162
+ #define XMLNS_BUFFER_LEN 128
163
+
160
164
  #endif
@@ -23,10 +23,34 @@ typedef xmlNodePtr (*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
23
23
  /* :nodoc: */
24
24
  static void relink_namespace(xmlNodePtr reparented)
25
25
  {
26
+ xmlChar *name, *prefix;
26
27
  xmlNodePtr child;
28
+ xmlNsPtr ns;
29
+
30
+ if (reparented->type != XML_ATTRIBUTE_NODE &&
31
+ reparented->type != XML_ELEMENT_NODE) return;
32
+
33
+ if (reparented->ns == NULL || reparented->ns->prefix == NULL) {
34
+ name = xmlSplitQName2(reparented->name, &prefix);
35
+
36
+ if(reparented->type == XML_ATTRIBUTE_NODE) {
37
+ if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) return;
38
+ }
39
+
40
+ ns = xmlSearchNs(reparented->doc, reparented, prefix);
41
+
42
+ if (ns == NULL && reparented->parent) {
43
+ ns = xmlSearchNs(reparented->doc, reparented->parent, prefix);
44
+ }
45
+
46
+ if (ns != NULL) {
47
+ xmlNodeSetName(reparented, name);
48
+ xmlSetNs(reparented, ns);
49
+ }
50
+ }
27
51
 
28
52
  /* Avoid segv when relinking against unlinked nodes. */
29
- if(!reparented->parent) return;
53
+ if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) return;
30
54
 
31
55
  /* Make sure that our reparented node has the correct namespaces */
32
56
  if(!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent)
@@ -70,6 +94,14 @@ static void relink_namespace(xmlNodePtr reparented)
70
94
  relink_namespace(child);
71
95
  child = child->next;
72
96
  }
97
+
98
+ if (reparented->type == XML_ELEMENT_NODE) {
99
+ child = (xmlNodePtr)((xmlElementPtr)reparented)->attributes;
100
+ while(NULL != child) {
101
+ relink_namespace(child);
102
+ child = child->next;
103
+ }
104
+ }
73
105
  }
74
106
 
75
107
  /* :nodoc: */
@@ -25,9 +25,6 @@ static int has_attributes(xmlTextReaderPtr reader)
25
25
  return(0);
26
26
  }
27
27
 
28
- #define XMLNS_PREFIX "xmlns"
29
- #define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
30
- #define XMLNS_BUFFER_LEN 128
31
28
  static void Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash)
32
29
  {
33
30
  xmlNsPtr ns;
@@ -120,7 +120,7 @@ module Nokogiri
120
120
  end
121
121
 
122
122
  def visit_class_condition node
123
- "contains(concat(' ', @class, ' '), ' #{node.value.first} ')"
123
+ "contains(concat(' ', normalize-space(@class), ' '), ' #{node.value.first} ')"
124
124
  end
125
125
 
126
126
  {
Binary file
@@ -1,6 +1,6 @@
1
1
  module Nokogiri
2
2
  # The version of Nokogiri you are using
3
- VERSION = '1.5.7.rc1'
3
+ VERSION = '1.5.7.rc2'
4
4
 
5
5
  class VersionInfo # :nodoc:
6
6
  def jruby?
@@ -327,7 +327,8 @@ module Nokogiri
327
327
  return self if @ns
328
328
  end
329
329
 
330
- raise ArgumentError, "Namespace #{ns} has not been defined"
330
+ @ns = { :pending => ns.to_s }
331
+ return self
331
332
  end
332
333
 
333
334
  ###
@@ -355,11 +356,20 @@ module Nokogiri
355
356
  else
356
357
  node = @doc.create_element(method.to_s.sub(/[_!]$/, ''),*args) { |n|
357
358
  # Set up the namespace
358
- if @ns
359
+ if @ns.is_a? Nokogiri::XML::Namespace
359
360
  n.namespace = @ns
360
361
  @ns = nil
361
362
  end
362
363
  }
364
+
365
+ if @ns.is_a? Hash
366
+ node.namespace = node.namespace_definitions.find { |x| x.prefix == @ns[:pending] }
367
+ if node.namespace.nil?
368
+ raise ArgumentError, "Namespace #{@ns[:pending]} has not been defined"
369
+ end
370
+ @ns = nil
371
+ end
372
+
363
373
  insert(node, &block)
364
374
  end
365
375
  end
@@ -87,7 +87,6 @@ module Nokogiri
87
87
  if key =~ NCNAME_RE
88
88
  ns_name = key.split(":", 2)[1]
89
89
  elm.add_namespace_definition ns_name, v
90
- next
91
90
  end
92
91
  elm[k.to_s] = v.to_s
93
92
  }
@@ -95,6 +94,9 @@ module Nokogiri
95
94
  elm.content = arg
96
95
  end
97
96
  end
97
+ if ns = elm.namespace_definitions.find { |n| n.prefix.nil? or n.prefix == '' }
98
+ elm.namespace = ns
99
+ end
98
100
  elm
99
101
  end
100
102
 
@@ -4,10 +4,10 @@ HOST = Rake::ExtensionCompiler.mingw_host
4
4
 
5
5
  require 'mini_portile'
6
6
  $recipes = {}
7
- $recipes[:zlib] = MiniPortile.new "zlib", "1.2.7"
8
- $recipes[:libiconv] = MiniPortile.new "libiconv", "1.13.1"
9
- $recipes[:libxml2] = MiniPortile.new "libxml2", "2.7.7"
10
- $recipes[:libxslt] = MiniPortile.new "libxslt", "1.1.26"
7
+ $recipes["zlib"] = MiniPortile.new "zlib", "1.2.7"
8
+ $recipes["libiconv"] = MiniPortile.new "libiconv", "1.13.1"
9
+ $recipes["libxml2"] = MiniPortile.new "libxml2", "2.7.7"
10
+ $recipes["libxslt"] = MiniPortile.new "libxslt", "1.1.26"
11
11
  $recipes.each { |_, recipe| recipe.host = HOST }
12
12
 
13
13
  file "lib/nokogiri/nokogiri.rb" do
@@ -18,7 +18,7 @@ end
18
18
 
19
19
  namespace :cross do
20
20
  task :zlib do
21
- recipe = $recipes[:zlib]
21
+ recipe = $recipes["zlib"]
22
22
  recipe.files = ["http://zlib.net/#{recipe.name}-#{recipe.version}.tar.gz"]
23
23
  class << recipe
24
24
  def configure
@@ -57,7 +57,7 @@ namespace :cross do
57
57
  end
58
58
 
59
59
  task :libiconv do
60
- recipe = $recipes[:libiconv]
60
+ recipe = $recipes["libiconv"]
61
61
  recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz"]
62
62
  recipe.configure_options = [
63
63
  "--host=#{HOST}",
@@ -78,14 +78,14 @@ namespace :cross do
78
78
  end
79
79
 
80
80
  task :libxml2 => ["cross:zlib", "cross:libiconv"] do
81
- recipe = $recipes[:libxml2]
81
+ recipe = $recipes["libxml2"]
82
82
  recipe.files = ["ftp://ftp.xmlsoft.org/libxml2/#{recipe.name}-#{recipe.version}.tar.gz"]
83
83
  recipe.configure_options = [
84
84
  "--host=#{HOST}",
85
85
  "--enable-static",
86
86
  "--disable-shared",
87
87
  "--with-zlib=#{CROSS_DIR}",
88
- "--with-iconv=#{$recipes[:libiconv].path}",
88
+ "--with-iconv=#{$recipes["libiconv"].path}",
89
89
  "--without-python",
90
90
  "--without-readline",
91
91
  "CFLAGS='-DIN_LIBXML'"
@@ -109,13 +109,13 @@ namespace :cross do
109
109
  end
110
110
 
111
111
  task :libxslt => ['cross:libxml2'] do
112
- recipe = $recipes[:libxslt]
112
+ recipe = $recipes["libxslt"]
113
113
  recipe.files = ["ftp://ftp.xmlsoft.org/libxml2/#{recipe.name}-#{recipe.version}.tar.gz"]
114
114
  recipe.configure_options = [
115
115
  "--host=#{HOST}",
116
116
  "--enable-static",
117
117
  "--disable-shared",
118
- "--with-libxml-prefix=#{$recipes[:libxml2].path}",
118
+ "--with-libxml-prefix=#{$recipes["libxml2"].path}",
119
119
  "--without-python",
120
120
  "--without-crypto",
121
121
  "CFLAGS='-DIN_LIBXML'"
@@ -263,33 +263,33 @@ module Nokogiri
263
263
  assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
264
264
  assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
265
265
  assert_xpath "//a[active(.)]", @parser.parse('a:active')
266
- assert_xpath "//a[active(.) and contains(concat(' ', @class, ' '), ' foo ')]",
266
+ assert_xpath "//a[active(.) and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]",
267
267
  @parser.parse('a:active.foo')
268
268
  end
269
269
 
270
270
  def test_star
271
271
  assert_xpath "//*", @parser.parse('*')
272
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
272
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' pastoral ')]",
273
273
  @parser.parse('*.pastoral')
274
274
  end
275
275
 
276
276
  def test_class
277
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
277
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' a ') and contains(concat(' ', normalize-space(@class), ' '), ' b ')]",
278
278
  @parser.parse('.a.b')
279
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
279
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
280
280
  @parser.parse('.awesome')
281
- assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
281
+ assert_xpath "//foo[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
282
282
  @parser.parse('foo.awesome')
283
- assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
283
+ assert_xpath "//foo//*[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
284
284
  @parser.parse('foo .awesome')
285
285
  end
286
286
 
287
287
  def test_not_so_simple_not
288
- assert_xpath "//*[@id = 'p' and not(contains(concat(' ', @class, ' '), ' a '))]",
288
+ assert_xpath "//*[@id = 'p' and not(contains(concat(' ', normalize-space(@class), ' '), ' a '))]",
289
289
  @parser.parse('#p:not(.a)')
290
- assert_xpath "//p[contains(concat(' ', @class, ' '), ' a ') and not(contains(concat(' ', @class, ' '), ' b '))]",
290
+ assert_xpath "//p[contains(concat(' ', normalize-space(@class), ' '), ' a ') and not(contains(concat(' ', normalize-space(@class), ' '), ' b '))]",
291
291
  @parser.parse('p.a:not(.b)')
292
- assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', @class, ' '), ' b '))]",
292
+ assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', normalize-space(@class), ' '), ' b '))]",
293
293
  @parser.parse("p[a='foo']:not(.b)")
294
294
  end
295
295
 
@@ -45,7 +45,7 @@ module Nokogiri
45
45
  end
46
46
 
47
47
  def test_class_selectors
48
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' red ')]",
48
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' red ')]",
49
49
  @parser.parse(".red")
50
50
  end
51
51
 
@@ -17,8 +17,7 @@ module Nokogiri
17
17
 
18
18
  def test_parse_empty_file
19
19
  # Make sure empty files don't break stuff
20
- empty_file_name = File.join(Dir.tmpdir, 'bogus.xml')
21
- FileUtils.touch empty_file_name
20
+ empty_file_name = File.join(ASSETS_DIR, 'bogus.xml')
22
21
  # assert_nothing_raised do
23
22
  @parser.parse_file empty_file_name
24
23
  # end