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.
- data/CHANGELOG.ja.rdoc +40 -11
- data/CHANGELOG.rdoc +32 -11
- data/Manifest.txt +1 -0
- data/Rakefile +20 -9
- data/ext/java/nokogiri/XmlDocument.java +4 -4
- data/ext/java/nokogiri/XmlNode.java +48 -20
- data/ext/java/nokogiri/internals/NokogiriHelpers.java +17 -2
- data/ext/java/nokogiri/internals/NokogiriNamespaceCache.java +18 -1
- data/ext/java/nokogiri/internals/UncloseableInputStream.java +102 -0
- data/ext/nokogiri/nokogiri.h +4 -0
- data/ext/nokogiri/xml_node.c +33 -1
- data/ext/nokogiri/xml_reader.c +0 -3
- data/lib/nokogiri/css/xpath_visitor.rb +1 -1
- data/lib/nokogiri/nokogiri.jar +0 -0
- data/lib/nokogiri/version.rb +1 -1
- data/lib/nokogiri/xml/builder.rb +12 -2
- data/lib/nokogiri/xml/document.rb +3 -1
- data/tasks/cross_compile.rb +10 -10
- data/test/css/test_parser.rb +9 -9
- data/test/css/test_xpath_visitor.rb +1 -1
- data/test/html/sax/test_parser.rb +1 -2
- data/test/namespaces/test_namespaces_in_builder_doc.rb +60 -0
- data/test/namespaces/test_namespaces_in_created_doc.rb +62 -0
- data/test/namespaces/test_namespaces_in_parsed_doc.rb +60 -0
- data/test/xml/test_builder.rb +17 -1
- data/test/xml/test_document.rb +4 -2
- data/test/xml/test_node.rb +13 -1
- data/test_all +1 -1
- metadata +79 -72
@@ -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
|
641
|
+
return tagName;
|
639
642
|
} else {
|
640
|
-
return newPrefix + ":" +
|
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.
|
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
|
+
}
|
data/ext/nokogiri/nokogiri.h
CHANGED
data/ext/nokogiri/xml_node.c
CHANGED
@@ -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: */
|
data/ext/nokogiri/xml_reader.c
CHANGED
@@ -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;
|
data/lib/nokogiri/nokogiri.jar
CHANGED
Binary file
|
data/lib/nokogiri/version.rb
CHANGED
data/lib/nokogiri/xml/builder.rb
CHANGED
@@ -327,7 +327,8 @@ module Nokogiri
|
|
327
327
|
return self if @ns
|
328
328
|
end
|
329
329
|
|
330
|
-
|
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
|
|
data/tasks/cross_compile.rb
CHANGED
@@ -4,10 +4,10 @@ HOST = Rake::ExtensionCompiler.mingw_host
|
|
4
4
|
|
5
5
|
require 'mini_portile'
|
6
6
|
$recipes = {}
|
7
|
-
$recipes[
|
8
|
-
$recipes[
|
9
|
-
$recipes[
|
10
|
-
$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"
|
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[
|
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[
|
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[
|
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[
|
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[
|
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[
|
118
|
+
"--with-libxml-prefix=#{$recipes["libxml2"].path}",
|
119
119
|
"--without-python",
|
120
120
|
"--without-crypto",
|
121
121
|
"CFLAGS='-DIN_LIBXML'"
|
data/test/css/test_parser.rb
CHANGED
@@ -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
|
|
@@ -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(
|
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
|