nokogiri 1.7.2-java → 1.8.0-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.cross_rubies +4 -4
- data/.travis.yml +43 -24
- data/CHANGELOG.md +54 -6
- data/Gemfile +8 -7
- data/Gemfile-libxml-ruby +3 -0
- data/LICENSE-DEPENDENCIES.md +1612 -0
- data/{LICENSE.txt → LICENSE.md} +1 -1
- data/Manifest.txt +5 -8
- data/README.md +8 -5
- data/Rakefile +15 -31
- data/appveyor.yml +2 -0
- data/dependencies.yml +12 -7
- data/ext/java/nokogiri/HtmlDocument.java +2 -2
- data/ext/java/nokogiri/HtmlSaxParserContext.java +20 -21
- data/ext/java/nokogiri/HtmlSaxPushParser.java +6 -10
- data/ext/java/nokogiri/NokogiriService.java +10 -31
- data/ext/java/nokogiri/XmlAttr.java +1 -26
- data/ext/java/nokogiri/XmlCdata.java +0 -1
- data/ext/java/nokogiri/XmlComment.java +1 -1
- data/ext/java/nokogiri/XmlDocument.java +4 -5
- data/ext/java/nokogiri/XmlDocumentFragment.java +29 -21
- data/ext/java/nokogiri/XmlDtd.java +1 -1
- data/ext/java/nokogiri/XmlElement.java +9 -10
- data/ext/java/nokogiri/XmlEntityDecl.java +4 -5
- data/ext/java/nokogiri/XmlNode.java +105 -103
- data/ext/java/nokogiri/XmlNodeSet.java +64 -76
- data/ext/java/nokogiri/XmlReader.java +48 -48
- data/ext/java/nokogiri/XmlRelaxng.java +1 -1
- data/ext/java/nokogiri/XmlSaxPushParser.java +37 -17
- data/ext/java/nokogiri/XmlSchema.java +7 -5
- data/ext/java/nokogiri/XmlSyntaxError.java +47 -35
- data/ext/java/nokogiri/XmlXpathContext.java +160 -132
- data/ext/java/nokogiri/XsltStylesheet.java +15 -24
- data/ext/java/nokogiri/internals/HtmlDomParserContext.java +19 -23
- data/ext/java/nokogiri/internals/NokogiriDomParser.java +1 -1
- data/ext/java/nokogiri/internals/NokogiriEncodingReaderWrapper.java +1 -1
- data/ext/java/nokogiri/internals/NokogiriEntityResolver.java +11 -13
- data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +5 -21
- data/ext/java/nokogiri/internals/NokogiriHandler.java +1 -1
- data/ext/java/nokogiri/internals/NokogiriHelpers.java +105 -142
- data/ext/java/nokogiri/internals/NokogiriNamespaceContext.java +16 -26
- data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +32 -50
- data/ext/java/nokogiri/internals/NokogiriXPathFunctionResolver.java +10 -13
- data/ext/java/nokogiri/internals/NokogiriXPathVariableResolver.java +3 -10
- data/ext/java/nokogiri/internals/ParserContext.java +4 -8
- data/ext/java/nokogiri/internals/ReaderNode.java +53 -93
- data/ext/java/nokogiri/internals/SaveContextVisitor.java +77 -89
- data/ext/java/nokogiri/internals/SchemaErrorHandler.java +6 -9
- data/ext/java/nokogiri/internals/XalanDTMManagerPatch.java +167 -0
- data/ext/java/nokogiri/internals/XmlDomParserContext.java +17 -6
- data/ext/java/nokogiri/internals/c14n/Canonicalizer.java +1 -1
- data/ext/java/nokogiri/internals/c14n/Canonicalizer11.java +28 -28
- data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315.java +3 -4
- data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315Excl.java +2 -2
- data/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java +10 -10
- data/ext/java/nokogiri/internals/c14n/ElementProxy.java +5 -5
- data/ext/java/nokogiri/internals/c14n/InclusiveNamespaces.java +2 -2
- data/ext/java/nokogiri/internals/c14n/NameSpaceSymbTable.java +1 -1
- data/ext/java/nokogiri/internals/c14n/XMLUtils.java +2 -2
- data/ext/java/org/apache/xml/dtm/ref/dom2dtm/DOM2DTMExt.java +1749 -0
- data/ext/nokogiri/extconf.rb +12 -17
- data/ext/nokogiri/nokogiri.h +0 -10
- data/ext/nokogiri/xml_attr.c +12 -8
- data/ext/nokogiri/xml_node.c +17 -14
- data/ext/nokogiri/xml_sax_push_parser.c +56 -12
- data/lib/nokogiri/html/sax/parser.rb +10 -0
- data/lib/nokogiri/nokogiri.jar +0 -0
- data/lib/nokogiri/version.rb +5 -4
- data/lib/nokogiri/xml/document.rb +9 -9
- data/lib/nokogiri/xml/node.rb +7 -7
- data/lib/nokogiri/xml/node_set.rb +12 -7
- data/lib/nokogiri/xml/sax/parser.rb +6 -7
- data/lib/nokogiri/xml/searchable.rb +34 -25
- data/lib/nokogiri/xml/syntax_error.rb +24 -1
- data/test/decorators/test_slop.rb +4 -1
- data/test/helper.rb +10 -0
- data/test/html/sax/test_parser.rb +27 -0
- data/test/html/test_document.rb +12 -1
- data/test/html/test_document_encoding.rb +1 -3
- data/test/html/test_document_fragment.rb +3 -0
- data/test/xml/sax/test_push_parser.rb +48 -0
- data/test/xml/test_attr.rb +7 -0
- data/test/xml/test_document.rb +1 -1
- data/test/xml/test_document_fragment.rb +27 -0
- data/test/xml/test_entity_reference.rb +2 -2
- data/test/xml/test_node.rb +12 -15
- data/test/xml/test_node_reparenting.rb +14 -0
- data/test/xml/test_node_set.rb +8 -6
- data/test/xml/test_reader.rb +19 -0
- data/test/xml/test_syntax_error.rb +21 -15
- data/test/xml/test_unparented_node.rb +54 -11
- data/test/xml/test_xpath.rb +23 -6
- metadata +32 -20
- data/ext/java/nokogiri/internals/NokogiriDocumentCache.java +0 -73
- data/ext/java/nokogiri/internals/XsltExtensionFunction.java +0 -72
- data/suppressions/nokogiri_ree-1.8.7.358.supp +0 -61
- data/suppressions/nokogiri_ruby-1.8.7.370.supp +0 -0
- data/suppressions/nokogiri_ruby-1.9.2.320.supp +0 -28
- data/suppressions/nokogiri_ruby-1.9.3.327.supp +0 -28
- data/test_all +0 -105
@@ -56,7 +56,7 @@ import org.w3c.dom.Node;
|
|
56
56
|
*/
|
57
57
|
|
58
58
|
@JRubyClass(name="Nokogiri::XML::Attr", parent="Nokogiri::XML::Node")
|
59
|
-
public class XmlAttr extends XmlNode{
|
59
|
+
public class XmlAttr extends XmlNode {
|
60
60
|
|
61
61
|
public static final String[] HTML_BOOLEAN_ATTRS = {
|
62
62
|
"checked", "compact", "declare", "defer", "disabled", "ismap",
|
@@ -117,31 +117,6 @@ public class XmlAttr extends XmlNode{
|
|
117
117
|
return false;
|
118
118
|
}
|
119
119
|
|
120
|
-
|
121
|
-
private String serializeAttrTextContent(String s, boolean htmlDoc) {
|
122
|
-
if (s == null) return "";
|
123
|
-
|
124
|
-
char[] c = s.toCharArray();
|
125
|
-
StringBuffer buffer = new StringBuffer(c.length);
|
126
|
-
|
127
|
-
for(int i = 0; i < c.length; i++) {
|
128
|
-
switch(c[i]){
|
129
|
-
case '\n': buffer.append(" "); break;
|
130
|
-
case '\r': buffer.append(" "); break;
|
131
|
-
case '\t': buffer.append("	"); break;
|
132
|
-
case '"': if (htmlDoc) buffer.append("%22");
|
133
|
-
else buffer.append(""");
|
134
|
-
break;
|
135
|
-
case '<': buffer.append("<"); break;
|
136
|
-
case '>': buffer.append(">"); break;
|
137
|
-
case '&': buffer.append("&"); break;
|
138
|
-
default: buffer.append(c[i]);
|
139
|
-
}
|
140
|
-
}
|
141
|
-
|
142
|
-
return buffer.toString();
|
143
|
-
}
|
144
|
-
|
145
120
|
@Override
|
146
121
|
@JRubyMethod(name = {"content", "value", "to_s"})
|
147
122
|
public IRubyObject content(ThreadContext context) {
|
@@ -70,7 +70,6 @@ public class XmlCdata extends XmlText {
|
|
70
70
|
IRubyObject doc = args[0];
|
71
71
|
content = args[1];
|
72
72
|
XmlDocument xmlDoc =(XmlDocument) ((XmlNode) doc).document(context);
|
73
|
-
doc = xmlDoc;
|
74
73
|
Document document = xmlDoc.getDocument();
|
75
74
|
Node node = document.createCDATASection((content.isNil()) ? null : rubyStringToString(content));
|
76
75
|
setNode(context, node);
|
@@ -249,7 +249,7 @@ public class XmlDocument extends XmlNode {
|
|
249
249
|
*/
|
250
250
|
@JRubyMethod(name="new", meta = true, rest = true, required=0)
|
251
251
|
public static IRubyObject rbNew(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
|
252
|
-
XmlDocument xmlDocument
|
252
|
+
XmlDocument xmlDocument;
|
253
253
|
try {
|
254
254
|
Document docNode = createNewDocument();
|
255
255
|
if ("Nokogiri::HTML::Document".equals(((RubyClass)klazz).getName())) {
|
@@ -281,8 +281,7 @@ public class XmlDocument extends XmlNode {
|
|
281
281
|
}
|
282
282
|
|
283
283
|
@Override
|
284
|
-
|
285
|
-
public IRubyObject document(ThreadContext context) {
|
284
|
+
IRubyObject document(Ruby runtime) {
|
286
285
|
return this;
|
287
286
|
}
|
288
287
|
|
@@ -575,7 +574,7 @@ public class XmlDocument extends XmlNode {
|
|
575
574
|
*/
|
576
575
|
@JRubyMethod(optional=3)
|
577
576
|
public IRubyObject canonicalize(ThreadContext context, IRubyObject[] args, Block block) {
|
578
|
-
|
577
|
+
int mode = 0;
|
579
578
|
String inclusive_namespace = null;
|
580
579
|
Boolean with_comments = false;
|
581
580
|
if (args.length > 0 && !(args[0].isNil())) {
|
@@ -586,7 +585,7 @@ public class XmlDocument extends XmlNode {
|
|
586
585
|
throw context.getRuntime().newTypeError("Expected array");
|
587
586
|
}
|
588
587
|
if (!args[1].isNil()) {
|
589
|
-
inclusive_namespace = (
|
588
|
+
inclusive_namespace = ((RubyArray)args[1])
|
590
589
|
.join(context, context.getRuntime().newString(" "))
|
591
590
|
.asString()
|
592
591
|
.asJavaString(); // OMG I wish I knew JRuby better, this is ugly
|
@@ -53,6 +53,7 @@ import org.jruby.anno.JRubyMethod;
|
|
53
53
|
import org.jruby.javasupport.util.RuntimeHelpers;
|
54
54
|
import org.jruby.runtime.ThreadContext;
|
55
55
|
import org.jruby.runtime.builtin.IRubyObject;
|
56
|
+
import org.jruby.util.ByteList;
|
56
57
|
import org.w3c.dom.Attr;
|
57
58
|
import org.w3c.dom.NamedNodeMap;
|
58
59
|
|
@@ -106,14 +107,12 @@ public class XmlDocumentFragment extends XmlNode {
|
|
106
107
|
return fragment;
|
107
108
|
}
|
108
109
|
|
109
|
-
private static
|
110
|
-
|
111
|
-
if (str.startsWith("<") && str.endsWith(">")) return true;
|
112
|
-
return false;
|
113
|
-
}
|
110
|
+
private static final ByteList TAG_BEG = ByteList.create("<");
|
111
|
+
private static final ByteList TAG_END = ByteList.create(">");
|
114
112
|
|
115
|
-
private static
|
116
|
-
|
113
|
+
private static boolean isTag(final RubyString str) {
|
114
|
+
return str.getByteList().startsWith(TAG_BEG) && str.getByteList().endsWith(TAG_END);
|
115
|
+
}
|
117
116
|
|
118
117
|
private static boolean isNamespaceDefined(String qName, NamedNodeMap nodeMap) {
|
119
118
|
if (isNamespace(qName.intern())) return true;
|
@@ -128,39 +127,48 @@ public class XmlDocumentFragment extends XmlNode {
|
|
128
127
|
}
|
129
128
|
return false;
|
130
129
|
}
|
131
|
-
|
130
|
+
|
131
|
+
private static final Pattern QNAME_RE = Pattern.compile("[^</:>\\s]+:[^</:>=\\s]+");
|
132
|
+
private static final Pattern START_TAG_RE = Pattern.compile("<[^</>]+>");
|
133
|
+
|
132
134
|
private static String addNamespaceDeclIfNeeded(XmlDocument doc, String tags) {
|
133
135
|
if (doc.getDocument() == null) return tags;
|
134
136
|
if (doc.getDocument().getDocumentElement() == null) return tags;
|
135
|
-
Matcher matcher =
|
136
|
-
Map<
|
137
|
-
while(matcher.find()) {
|
137
|
+
Matcher matcher = START_TAG_RE.matcher(tags);
|
138
|
+
Map<CharSequence, CharSequence> rewriteTable = null;
|
139
|
+
while (matcher.find()) {
|
138
140
|
String start_tag = matcher.group();
|
139
|
-
Matcher matcher2 =
|
140
|
-
while(matcher2.find()) {
|
141
|
+
Matcher matcher2 = QNAME_RE.matcher(start_tag);
|
142
|
+
while (matcher2.find()) {
|
141
143
|
String qName = matcher2.group();
|
142
144
|
NamedNodeMap nodeMap = doc.getDocument().getDocumentElement().getAttributes();
|
143
145
|
if (isNamespaceDefined(qName, nodeMap)) {
|
144
|
-
|
146
|
+
CharSequence namespaceDecl = getNamespaceDecl(getPrefix(qName), nodeMap);
|
145
147
|
if (namespaceDecl != null) {
|
146
|
-
rewriteTable
|
148
|
+
if (rewriteTable == null) rewriteTable = new HashMap(8, 1);
|
149
|
+
StringBuilder str = new StringBuilder(qName.length() + namespaceDecl.length() + 3);
|
150
|
+
String key = str.append('<').append(qName).append('>').toString();
|
151
|
+
str.setCharAt(key.length() - 1, ' '); // (last) '>' -> ' '
|
152
|
+
rewriteTable.put(key, str.append(namespaceDecl).append('>'));
|
147
153
|
}
|
148
154
|
}
|
149
155
|
}
|
150
156
|
}
|
151
|
-
|
152
|
-
|
153
|
-
|
157
|
+
if (rewriteTable != null) {
|
158
|
+
for (Map.Entry<CharSequence, CharSequence> e : rewriteTable.entrySet()) {
|
159
|
+
tags = tags.replace(e.getKey(), e.getValue());
|
160
|
+
}
|
154
161
|
}
|
155
162
|
|
156
163
|
return tags;
|
157
164
|
}
|
158
165
|
|
159
|
-
private static
|
166
|
+
private static CharSequence getNamespaceDecl(final String prefix, NamedNodeMap nodeMap) {
|
160
167
|
for (int i=0; i < nodeMap.getLength(); i++) {
|
161
|
-
Attr attr = (Attr)nodeMap.item(i);
|
168
|
+
Attr attr = (Attr) nodeMap.item(i);
|
162
169
|
if (prefix.equals(attr.getLocalName())) {
|
163
|
-
return
|
170
|
+
return new StringBuilder().
|
171
|
+
append(attr.getName()).append('=').append('"').append(attr.getValue()).append('"');
|
164
172
|
}
|
165
173
|
}
|
166
174
|
return null;
|
@@ -130,7 +130,7 @@ public class XmlDtd extends XmlNode {
|
|
130
130
|
IRubyObject external_id,
|
131
131
|
IRubyObject system_id) {
|
132
132
|
|
133
|
-
DocumentType placeholder
|
133
|
+
DocumentType placeholder;
|
134
134
|
if (doc.getDoctype() == null) {
|
135
135
|
String javaName = NokogiriHelpers.rubyStringToString(name);
|
136
136
|
String javaExternalId = NokogiriHelpers.rubyStringToString(external_id);
|
@@ -68,21 +68,20 @@ public class XmlElement extends XmlNode {
|
|
68
68
|
|
69
69
|
@Override
|
70
70
|
public void accept(ThreadContext context, SaveContextVisitor visitor) {
|
71
|
-
visitor.enter((Element)node);
|
71
|
+
visitor.enter((Element) node);
|
72
72
|
XmlNodeSet xmlNodeSet = (XmlNodeSet) children(context);
|
73
73
|
if (xmlNodeSet.length() > 0) {
|
74
|
-
RubyArray
|
75
|
-
for(int i = 0; i <
|
76
|
-
Object item =
|
74
|
+
RubyArray nodes = xmlNodeSet.nodes;
|
75
|
+
for( int i = 0; i < nodes.size(); i++ ) {
|
76
|
+
Object item = nodes.eltInternal(i);
|
77
77
|
if (item instanceof XmlNode) {
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
XmlNamespace
|
82
|
-
cur.accept(context, visitor);
|
78
|
+
((XmlNode) item).accept(context, visitor);
|
79
|
+
}
|
80
|
+
else if (item instanceof XmlNamespace) {
|
81
|
+
((XmlNamespace) item).accept(context, visitor);
|
83
82
|
}
|
84
83
|
}
|
85
84
|
}
|
86
|
-
visitor.leave((Element)node);
|
85
|
+
visitor.leave((Element) node);
|
87
86
|
}
|
88
87
|
}
|
@@ -37,7 +37,6 @@ import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
|
|
37
37
|
import org.jruby.Ruby;
|
38
38
|
import org.jruby.RubyClass;
|
39
39
|
import org.jruby.RubyFixnum;
|
40
|
-
import org.jruby.RubyNil;
|
41
40
|
import org.jruby.anno.JRubyClass;
|
42
41
|
import org.jruby.anno.JRubyMethod;
|
43
42
|
import org.jruby.runtime.ThreadContext;
|
@@ -117,7 +116,7 @@ public class XmlEntityDecl extends XmlNode {
|
|
117
116
|
@JRubyMethod
|
118
117
|
public IRubyObject node_name(ThreadContext context) {
|
119
118
|
IRubyObject value = getAttribute(context, "name");
|
120
|
-
if (value
|
119
|
+
if (value.isNil()) value = name;
|
121
120
|
return value;
|
122
121
|
}
|
123
122
|
|
@@ -131,7 +130,7 @@ public class XmlEntityDecl extends XmlNode {
|
|
131
130
|
@JRubyMethod
|
132
131
|
public IRubyObject content(ThreadContext context) {
|
133
132
|
IRubyObject value = getAttribute(context, "value");
|
134
|
-
if (value
|
133
|
+
if (value.isNil()) value = content;
|
135
134
|
return value;
|
136
135
|
}
|
137
136
|
|
@@ -144,14 +143,14 @@ public class XmlEntityDecl extends XmlNode {
|
|
144
143
|
@JRubyMethod
|
145
144
|
public IRubyObject system_id(ThreadContext context) {
|
146
145
|
IRubyObject value = getAttribute(context, "sysid");
|
147
|
-
if (value
|
146
|
+
if (value.isNil()) value = system_id;
|
148
147
|
return value;
|
149
148
|
}
|
150
149
|
|
151
150
|
@JRubyMethod
|
152
151
|
public IRubyObject external_id(ThreadContext context) {
|
153
152
|
IRubyObject value = getAttribute(context, "pubid");
|
154
|
-
if (value
|
153
|
+
if (value.isNil()) value = external_id;
|
155
154
|
return value;
|
156
155
|
}
|
157
156
|
|
@@ -36,6 +36,8 @@ import static java.lang.Math.max;
|
|
36
36
|
import static nokogiri.internals.NokogiriHelpers.getCachedNodeOrCreate;
|
37
37
|
import static nokogiri.internals.NokogiriHelpers.clearCachedNode;
|
38
38
|
import static nokogiri.internals.NokogiriHelpers.clearXpathContext;
|
39
|
+
import static nokogiri.internals.NokogiriHelpers.convertEncoding;
|
40
|
+
import static nokogiri.internals.NokogiriHelpers.convertString;
|
39
41
|
import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
|
40
42
|
import static nokogiri.internals.NokogiriHelpers.nodeArrayToRubyArray;
|
41
43
|
import static nokogiri.internals.NokogiriHelpers.nonEmptyStringOrNil;
|
@@ -44,6 +46,7 @@ import static nokogiri.internals.NokogiriHelpers.stringOrNil;
|
|
44
46
|
|
45
47
|
import java.io.ByteArrayInputStream;
|
46
48
|
import java.io.InputStream;
|
49
|
+
import java.nio.ByteBuffer;
|
47
50
|
import java.nio.charset.CharacterCodingException;
|
48
51
|
import java.nio.charset.Charset;
|
49
52
|
import java.util.ArrayList;
|
@@ -60,6 +63,7 @@ import org.apache.xerces.dom.CoreDocumentImpl;
|
|
60
63
|
import org.jruby.Ruby;
|
61
64
|
import org.jruby.RubyArray;
|
62
65
|
import org.jruby.RubyClass;
|
66
|
+
import org.jruby.RubyInteger;
|
63
67
|
import org.jruby.RubyFixnum;
|
64
68
|
import org.jruby.RubyModule;
|
65
69
|
import org.jruby.RubyObject;
|
@@ -72,6 +76,7 @@ import org.jruby.runtime.Block;
|
|
72
76
|
import org.jruby.runtime.ThreadContext;
|
73
77
|
import org.jruby.runtime.Visibility;
|
74
78
|
import org.jruby.runtime.builtin.IRubyObject;
|
79
|
+
import org.jruby.util.ByteList;
|
75
80
|
import org.w3c.dom.Attr;
|
76
81
|
import org.w3c.dom.Document;
|
77
82
|
import org.w3c.dom.DocumentFragment;
|
@@ -119,12 +124,11 @@ public class XmlNode extends RubyObject {
|
|
119
124
|
* in <code>context</code>.
|
120
125
|
*/
|
121
126
|
protected static XmlNode asXmlNode(ThreadContext context, IRubyObject node) {
|
122
|
-
if (
|
123
|
-
Ruby
|
124
|
-
throw
|
125
|
-
} else {
|
126
|
-
return (XmlNode) node;
|
127
|
+
if ( !(node instanceof XmlNode) ) {
|
128
|
+
final Ruby runtime = context.getRuntime();
|
129
|
+
throw runtime.newTypeError(node == null ? runtime.getNil() : node, getNokogiriClass(runtime, "Nokogiri::XML::Node"));
|
127
130
|
}
|
131
|
+
return (XmlNode) node;
|
128
132
|
}
|
129
133
|
|
130
134
|
/**
|
@@ -132,11 +136,8 @@ public class XmlNode extends RubyObject {
|
|
132
136
|
* raise a type error in <code>context</code>.
|
133
137
|
*/
|
134
138
|
protected static XmlNode asXmlNodeOrNull(ThreadContext context, IRubyObject node) {
|
135
|
-
if (node == null || node.isNil())
|
136
|
-
|
137
|
-
} else {
|
138
|
-
return asXmlNode(context, node);
|
139
|
-
}
|
139
|
+
if (node == null || node.isNil()) return null;
|
140
|
+
return asXmlNode(context, node);
|
140
141
|
}
|
141
142
|
|
142
143
|
/**
|
@@ -219,15 +220,15 @@ public class XmlNode extends RubyObject {
|
|
219
220
|
setNode(ruby.getCurrentContext(), node);
|
220
221
|
}
|
221
222
|
|
222
|
-
protected void decorate(
|
223
|
+
protected void decorate(final ThreadContext context) {
|
223
224
|
if (node != null) {
|
224
225
|
resetCache();
|
225
226
|
|
226
227
|
if (node.getNodeType() != Node.DOCUMENT_NODE) {
|
227
|
-
doc = document(
|
228
|
+
doc = document(context.runtime);
|
228
229
|
|
229
|
-
if (doc != null && doc.
|
230
|
-
RuntimeHelpers.invoke(
|
230
|
+
if (doc != null && ! doc.isNil()) {
|
231
|
+
RuntimeHelpers.invoke(context, doc, "decorate", this);
|
231
232
|
}
|
232
233
|
}
|
233
234
|
}
|
@@ -290,14 +291,14 @@ public class XmlNode extends RubyObject {
|
|
290
291
|
Ruby ruby = context.getRuntime();
|
291
292
|
RubyClass klazz = (RubyClass) cls;
|
292
293
|
|
293
|
-
if (
|
294
|
+
if ("Nokogiri::XML::Node".equals(klazz.getName())) {
|
294
295
|
klazz = getNokogiriClass(ruby, "Nokogiri::XML::Element");
|
295
296
|
}
|
296
297
|
|
297
298
|
XmlNode xmlNode = (XmlNode) klazz.allocate();
|
298
299
|
xmlNode.init(context, args);
|
299
300
|
xmlNode.callInit(args, block);
|
300
|
-
|
301
|
+
assert xmlNode.node != null;
|
301
302
|
if (block.isGiven()) block.call(context, xmlNode);
|
302
303
|
return xmlNode;
|
303
304
|
}
|
@@ -330,7 +331,7 @@ public class XmlNode extends RubyObject {
|
|
330
331
|
throw getRuntime().newArgumentError("node must have owner document");
|
331
332
|
}
|
332
333
|
|
333
|
-
Element element
|
334
|
+
Element element;
|
334
335
|
String node_name = rubyStringToString(name);
|
335
336
|
String prefix = NokogiriHelpers.getPrefix(node_name);
|
336
337
|
String namespace_uri = null;
|
@@ -380,7 +381,7 @@ public class XmlNode extends RubyObject {
|
|
380
381
|
boolean closingTag = false;
|
381
382
|
String indentString = rubyStringToString(indentStringObject);
|
382
383
|
int lengthInd = indentString.length();
|
383
|
-
|
384
|
+
StringBuilder curInd = new StringBuilder();
|
384
385
|
|
385
386
|
resultLines[0] = lines[0];
|
386
387
|
|
@@ -404,10 +405,9 @@ public class XmlNode extends RubyObject {
|
|
404
405
|
closingTag = false;
|
405
406
|
}
|
406
407
|
|
407
|
-
|
408
|
+
StringBuilder result = new StringBuilder();
|
408
409
|
for(int i = 0; i < resultLines.length; i++) {
|
409
|
-
result.append(resultLines[i]);
|
410
|
-
result.append("\n");
|
410
|
+
result.append(resultLines[i]).append('\n');
|
411
411
|
}
|
412
412
|
|
413
413
|
return result.toString();
|
@@ -479,7 +479,7 @@ public class XmlNode extends RubyObject {
|
|
479
479
|
String nsURI = e.lookupNamespaceURI(prefix);
|
480
480
|
this.node = NokogiriHelpers.renameNode(e, nsURI, e.getNodeName());
|
481
481
|
|
482
|
-
if (nsURI == null || nsURI
|
482
|
+
if (nsURI == null || nsURI.isEmpty()) {
|
483
483
|
return;
|
484
484
|
}
|
485
485
|
|
@@ -488,12 +488,12 @@ public class XmlNode extends RubyObject {
|
|
488
488
|
|
489
489
|
for (int i = 0; i < attrs.getLength(); i++) {
|
490
490
|
Attr attr = (Attr) attrs.item(i);
|
491
|
-
String nsUri = "";
|
492
491
|
String attrPrefix = attr.getPrefix();
|
493
492
|
if (attrPrefix == null) {
|
494
493
|
attrPrefix = NokogiriHelpers.getPrefix(attr.getNodeName());
|
495
494
|
}
|
496
495
|
String nodeName = attr.getNodeName();
|
496
|
+
String nsUri;
|
497
497
|
if ("xml".equals(attrPrefix)) {
|
498
498
|
nsUri = "http://www.w3.org/XML/1998/namespace";
|
499
499
|
} else if ("xmlns".equals(attrPrefix) || nodeName.equals("xmlns")) {
|
@@ -549,16 +549,22 @@ public class XmlNode extends RubyObject {
|
|
549
549
|
|
550
550
|
public void setDocument(ThreadContext context, IRubyObject doc) {
|
551
551
|
this.doc = doc;
|
552
|
-
|
552
|
+
|
553
|
+
setDocumentAndDecorate(context, this, doc);
|
554
|
+
}
|
555
|
+
|
556
|
+
// shared logic with XmlNodeSet
|
557
|
+
static void setDocumentAndDecorate(ThreadContext context, RubyObject self, IRubyObject doc) {
|
558
|
+
self.setInstanceVariable("@document", doc);
|
553
559
|
if (doc != null) {
|
554
|
-
RuntimeHelpers.invoke(context, doc, "decorate",
|
560
|
+
RuntimeHelpers.invoke(context, doc, "decorate", self);
|
555
561
|
}
|
556
562
|
}
|
557
563
|
|
558
564
|
public void setNode(ThreadContext context, Node node) {
|
559
565
|
this.node = node;
|
560
566
|
|
561
|
-
decorate(context
|
567
|
+
decorate(context);
|
562
568
|
|
563
569
|
if (this instanceof XmlAttr) {
|
564
570
|
((XmlAttr)this).setNamespaceIfNecessary(context.getRuntime());
|
@@ -583,17 +589,15 @@ public class XmlNode extends RubyObject {
|
|
583
589
|
|
584
590
|
protected IRubyObject getNodeName(ThreadContext context) {
|
585
591
|
if (name != null) return name;
|
586
|
-
String str = null;
|
587
592
|
|
588
|
-
|
593
|
+
String str = null;
|
594
|
+
if (node != null) {
|
589
595
|
str = node.getNodeName();
|
590
596
|
str = NokogiriHelpers.getLocalPart(str);
|
591
597
|
}
|
592
598
|
if (str == null) str = "";
|
593
599
|
if (str.startsWith("#")) str = str.substring(1); // eliminates '#'
|
594
|
-
name = NokogiriHelpers.stringOrBlank(context.getRuntime(), str);
|
595
|
-
|
596
|
-
return name;
|
600
|
+
return name = NokogiriHelpers.stringOrBlank(context.getRuntime(), str);
|
597
601
|
}
|
598
602
|
|
599
603
|
/**
|
@@ -696,10 +700,9 @@ public class XmlNode extends RubyObject {
|
|
696
700
|
// a node is blank if if it is a Text or CDATA node consisting of whitespace only
|
697
701
|
if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE) {
|
698
702
|
String data = node.getTextContent();
|
699
|
-
|
700
|
-
if ("".equals(data.trim())) return context.getRuntime().getTrue();
|
703
|
+
return context.runtime.newBoolean(data == null || data.isEmpty() || data.trim().isEmpty());
|
701
704
|
}
|
702
|
-
return context.
|
705
|
+
return context.runtime.getFalse();
|
703
706
|
}
|
704
707
|
|
705
708
|
@JRubyMethod
|
@@ -709,8 +712,16 @@ public class XmlNode extends RubyObject {
|
|
709
712
|
|
710
713
|
@JRubyMethod
|
711
714
|
public IRubyObject children(ThreadContext context) {
|
712
|
-
XmlNodeSet xmlNodeSet =
|
713
|
-
|
715
|
+
XmlNodeSet xmlNodeSet = XmlNodeSet.create(context.runtime);
|
716
|
+
|
717
|
+
NodeList nodeList = node.getChildNodes();
|
718
|
+
if (nodeList.getLength() > 0) {
|
719
|
+
xmlNodeSet.setNodeList(nodeList); // initializes @document from first node
|
720
|
+
}
|
721
|
+
else { // TODO this is very ripe for refactoring
|
722
|
+
setDocumentAndDecorate(context, xmlNodeSet, doc);
|
723
|
+
}
|
724
|
+
|
714
725
|
return xmlNodeSet;
|
715
726
|
}
|
716
727
|
|
@@ -815,13 +826,11 @@ public class XmlNode extends RubyObject {
|
|
815
826
|
ctx = new HtmlDomParserContext(runtime, options);
|
816
827
|
((HtmlDomParserContext)ctx).enableDocumentFragment();
|
817
828
|
istream = new ByteArrayInputStream((rubyStringToString(str)).getBytes());
|
818
|
-
} else
|
829
|
+
} else {
|
819
830
|
klass = getNokogiriClass(runtime, "Nokogiri::XML::Document");
|
820
831
|
ctx = new XmlDomParserContext(runtime, options);
|
821
832
|
String input = rubyStringToString(str);
|
822
833
|
istream = new ByteArrayInputStream(input.getBytes());
|
823
|
-
} else {
|
824
|
-
return runtime.getNil();
|
825
834
|
}
|
826
835
|
|
827
836
|
ctx.setInputSource(istream);
|
@@ -869,84 +878,86 @@ public class XmlNode extends RubyObject {
|
|
869
878
|
}
|
870
879
|
|
871
880
|
private boolean isErrorIncreased(RubyArray baseErrors, RubyArray createdErrors) {
|
872
|
-
|
873
|
-
|
874
|
-
return diff_in_length > 0;
|
881
|
+
int length = ((RubyArray) createdErrors.op_diff(baseErrors)).size();
|
882
|
+
return length > 0;
|
875
883
|
}
|
876
884
|
|
877
885
|
@JRubyMethod(name = {"content", "text", "inner_text"})
|
878
886
|
public IRubyObject content(ThreadContext context) {
|
887
|
+
return stringOrNil(context.getRuntime(), getContentImpl());
|
888
|
+
}
|
889
|
+
|
890
|
+
public CharSequence getContentImpl() {
|
879
891
|
if (!node.hasChildNodes() && node.getNodeValue() == null &&
|
880
|
-
(node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE))
|
881
|
-
|
882
|
-
|
892
|
+
(node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE)) {
|
893
|
+
return null;
|
894
|
+
}
|
895
|
+
CharSequence textContent;
|
883
896
|
if (this instanceof XmlDocument) {
|
884
897
|
Node node = ((Document)this.node).getDocumentElement();
|
885
898
|
if (node == null) {
|
886
899
|
textContent = "";
|
887
900
|
} else {
|
888
|
-
Node documentElement = ((Document)this.node).getDocumentElement();
|
889
|
-
|
890
|
-
getTextContentRecursively(context, buffer, documentElement);
|
891
|
-
textContent = buffer.toString();
|
901
|
+
Node documentElement = ((Document) this.node).getDocumentElement();
|
902
|
+
textContent = getTextContentRecursively(new StringBuilder(), documentElement);
|
892
903
|
}
|
893
904
|
} else {
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
textContent
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
getTextContentRecursively(context, buffer, child);
|
913
|
-
}
|
905
|
+
textContent = getTextContentRecursively(new StringBuilder(), node);
|
906
|
+
}
|
907
|
+
// textContent = NokogiriHelpers.convertEncodingByNKFIfNecessary(context, (XmlDocument) document(context), textContent);
|
908
|
+
return textContent;
|
909
|
+
}
|
910
|
+
|
911
|
+
private StringBuilder getTextContentRecursively(StringBuilder buffer, Node currentNode) {
|
912
|
+
CharSequence textContent = currentNode.getNodeValue();
|
913
|
+
if (textContent != null && NokogiriHelpers.shouldDecode(currentNode)) {
|
914
|
+
textContent = NokogiriHelpers.decodeJavaString(textContent);
|
915
|
+
}
|
916
|
+
if (textContent != null) buffer.append(textContent);
|
917
|
+
NodeList children = currentNode.getChildNodes();
|
918
|
+
for (int i = 0; i < children.getLength(); i++) {
|
919
|
+
Node child = children.item(i);
|
920
|
+
if (hasTextContent(child)) getTextContentRecursively(buffer, child);
|
921
|
+
}
|
922
|
+
return buffer;
|
914
923
|
}
|
915
924
|
|
916
925
|
private boolean hasTextContent(Node child) {
|
917
|
-
|
918
|
-
child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE;
|
926
|
+
return child.getNodeType() != Node.COMMENT_NODE && child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE;
|
919
927
|
}
|
920
928
|
|
921
929
|
@JRubyMethod
|
922
|
-
public IRubyObject document(ThreadContext context) {
|
930
|
+
public final IRubyObject document(ThreadContext context) {
|
931
|
+
return document(context.runtime);
|
932
|
+
}
|
933
|
+
|
934
|
+
IRubyObject document(final Ruby runtime) {
|
923
935
|
if (doc == null) {
|
924
936
|
doc = (XmlDocument) node.getOwnerDocument().getUserData(NokogiriHelpers.CACHED_NODE);
|
925
937
|
}
|
926
938
|
if (doc == null) {
|
927
|
-
doc = getCachedNodeOrCreate(
|
939
|
+
doc = getCachedNodeOrCreate(runtime, node.getOwnerDocument());
|
928
940
|
node.getOwnerDocument().setUserData(NokogiriHelpers.CACHED_NODE, doc, null);
|
929
941
|
}
|
930
942
|
return doc;
|
931
943
|
}
|
932
944
|
|
933
945
|
public IRubyObject dup() {
|
934
|
-
return
|
946
|
+
return dup_implementation(getMetaClass().getClassRuntime(), true);
|
935
947
|
}
|
936
948
|
|
937
949
|
@JRubyMethod
|
938
950
|
public IRubyObject dup(ThreadContext context) {
|
939
|
-
return
|
951
|
+
return dup_implementation(context, true);
|
940
952
|
}
|
941
953
|
|
942
954
|
@JRubyMethod
|
943
955
|
public IRubyObject dup(ThreadContext context, IRubyObject depth) {
|
944
|
-
boolean deep =
|
945
|
-
|
946
|
-
return this.dup_implementation(context, deep);
|
956
|
+
boolean deep = depth instanceof RubyInteger && RubyFixnum.fix2int(depth) != 0;
|
957
|
+
return dup_implementation(context, deep);
|
947
958
|
}
|
948
959
|
|
949
|
-
protected IRubyObject dup_implementation(ThreadContext context, boolean deep) {
|
960
|
+
protected final IRubyObject dup_implementation(ThreadContext context, boolean deep) {
|
950
961
|
return dup_implementation(context.getRuntime(), deep);
|
951
962
|
}
|
952
963
|
|
@@ -957,17 +968,14 @@ public class XmlNode extends RubyObject {
|
|
957
968
|
} catch (CloneNotSupportedException e) {
|
958
969
|
throw runtime.newRuntimeError(e.toString());
|
959
970
|
}
|
960
|
-
if (node == null) throw runtime.newRuntimeError("FFFFFFFFFUUUUUUU");
|
961
971
|
Node newNode = node.cloneNode(deep);
|
962
972
|
clone.node = newNode;
|
963
973
|
return clone;
|
964
974
|
}
|
965
975
|
|
966
|
-
public static
|
967
|
-
|
968
|
-
|
969
|
-
String enc = NokogiriHelpers.encodeJavaString(s);
|
970
|
-
return context.getRuntime().newString(enc);
|
976
|
+
public static RubyString encode_special_chars(ThreadContext context, IRubyObject string) {
|
977
|
+
CharSequence str = NokogiriHelpers.encodeJavaString( rubyStringToString(string) );
|
978
|
+
return RubyString.newString(context.getRuntime(), str);
|
971
979
|
}
|
972
980
|
|
973
981
|
/**
|
@@ -1206,7 +1214,7 @@ public class XmlNode extends RubyObject {
|
|
1206
1214
|
protected void setContent(IRubyObject content) {
|
1207
1215
|
String javaContent = rubyStringToString(content);
|
1208
1216
|
node.setTextContent(javaContent);
|
1209
|
-
if (javaContent.length() == 0) return;
|
1217
|
+
if (javaContent == null || javaContent.length() == 0) return;
|
1210
1218
|
if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE) return;
|
1211
1219
|
if (node.getFirstChild() != null) {
|
1212
1220
|
node.getFirstChild().setUserData(NokogiriHelpers.ENCODED_STRING, true, null);
|
@@ -1260,19 +1268,16 @@ public class XmlNode extends RubyObject {
|
|
1260
1268
|
String encString = encoding.isNil() ? null : rubyStringToString(encoding);
|
1261
1269
|
|
1262
1270
|
SaveContextVisitor visitor =
|
1263
|
-
new SaveContextVisitor((
|
1271
|
+
new SaveContextVisitor(RubyFixnum.fix2int(options), rubyStringToString(indentString), encString, isHtmlDoc(context), isFragment(), 0);
|
1264
1272
|
accept(context, visitor);
|
1265
1273
|
|
1266
|
-
IRubyObject rubyString
|
1274
|
+
final IRubyObject rubyString;
|
1267
1275
|
if (NokogiriHelpers.isUTF8(encString)) {
|
1268
|
-
rubyString =
|
1276
|
+
rubyString = convertString(context.getRuntime(), visitor.getInternalBuffer());
|
1269
1277
|
} else {
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
} catch (CharacterCodingException e) {
|
1274
|
-
throw context.getRuntime().newRuntimeError(e.getMessage());
|
1275
|
-
}
|
1278
|
+
ByteBuffer bytes = convertEncoding(Charset.forName(encString), visitor.getInternalBuffer());
|
1279
|
+
ByteList str = new ByteList(bytes.array(), bytes.arrayOffset(), bytes.remaining());
|
1280
|
+
rubyString = RubyString.newString(context.getRuntime(), str);
|
1276
1281
|
}
|
1277
1282
|
RuntimeHelpers.invoke(context, io, "write", rubyString);
|
1278
1283
|
|
@@ -1432,9 +1437,10 @@ public class XmlNode extends RubyObject {
|
|
1432
1437
|
|
1433
1438
|
@JRubyMethod(name = {"unlink", "remove"})
|
1434
1439
|
public IRubyObject unlink(ThreadContext context) {
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1440
|
+
final Node parent = node.getParentNode();
|
1441
|
+
if (parent != null) {
|
1442
|
+
parent.removeChild(node);
|
1443
|
+
clearXpathContext(parent);
|
1438
1444
|
}
|
1439
1445
|
return this;
|
1440
1446
|
}
|
@@ -1532,7 +1538,7 @@ public class XmlNode extends RubyObject {
|
|
1532
1538
|
}
|
1533
1539
|
|
1534
1540
|
protected enum AdoptScheme {
|
1535
|
-
CHILD, PREV_SIBLING, NEXT_SIBLING, REPLACEMENT
|
1541
|
+
CHILD, PREV_SIBLING, NEXT_SIBLING, REPLACEMENT
|
1536
1542
|
}
|
1537
1543
|
|
1538
1544
|
/**
|
@@ -1682,10 +1688,6 @@ public class XmlNode extends RubyObject {
|
|
1682
1688
|
|
1683
1689
|
Node nextSib = thisNode.getNextSibling();
|
1684
1690
|
|
1685
|
-
if (nextSib != null &&
|
1686
|
-
nextSib.getNodeType() == Node.TEXT_NODE &&
|
1687
|
-
otherNode.getNodeType() == Node.TEXT_NODE) return;
|
1688
|
-
|
1689
1691
|
if (nextSib != null) {
|
1690
1692
|
parent.insertBefore(otherNode, nextSib);
|
1691
1693
|
} else {
|