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
@@ -178,17 +178,19 @@ public class XmlSchema extends RubyObject {
|
|
178
178
|
|
179
179
|
IRubyObject validate_document_or_file(ThreadContext context, XmlDocument xmlDocument) {
|
180
180
|
RubyArray errors = (RubyArray) this.getInstanceVariable("@errors");
|
181
|
-
ErrorHandler errorHandler = new SchemaErrorHandler(context.
|
181
|
+
ErrorHandler errorHandler = new SchemaErrorHandler(context.runtime, errors);
|
182
182
|
setErrorHandler(errorHandler);
|
183
183
|
|
184
184
|
try {
|
185
185
|
validate(xmlDocument.getDocument());
|
186
|
-
}
|
187
|
-
|
186
|
+
}
|
187
|
+
catch (SAXException ex) {
|
188
|
+
XmlSyntaxError xmlSyntaxError = XmlSyntaxError.createXMLSyntaxError(context.runtime);
|
188
189
|
xmlSyntaxError.setException(ex);
|
189
190
|
errors.append(xmlSyntaxError);
|
190
|
-
}
|
191
|
-
|
191
|
+
}
|
192
|
+
catch (IOException ex) {
|
193
|
+
throw context.runtime.newIOError(ex.getMessage());
|
192
194
|
}
|
193
195
|
|
194
196
|
return errors;
|
@@ -32,7 +32,6 @@
|
|
32
32
|
|
33
33
|
package nokogiri;
|
34
34
|
|
35
|
-
import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
|
36
35
|
import static nokogiri.internals.NokogiriHelpers.stringOrNil;
|
37
36
|
|
38
37
|
import org.jruby.CompatVersion;
|
@@ -53,64 +52,72 @@ import org.xml.sax.SAXParseException;
|
|
53
52
|
*/
|
54
53
|
@JRubyClass(name="Nokogiri::XML::SyntaxError", parent="Nokogiri::SyntaxError")
|
55
54
|
public class XmlSyntaxError extends RubyException {
|
55
|
+
|
56
56
|
private Exception exception;
|
57
|
+
private boolean messageSet; // whether a custom error message was set
|
57
58
|
|
58
59
|
public XmlSyntaxError(Ruby runtime, RubyClass klazz) {
|
59
60
|
super(runtime, klazz);
|
60
61
|
}
|
61
62
|
|
62
|
-
/**
|
63
|
-
* Create and return a copy of this object.
|
64
|
-
*
|
65
|
-
* @return a clone of this object
|
66
|
-
*/
|
67
|
-
@Override
|
68
|
-
public Object clone() throws CloneNotSupportedException {
|
69
|
-
return super.clone();
|
70
|
-
}
|
71
|
-
|
72
63
|
public XmlSyntaxError(Ruby runtime, RubyClass rubyClass, Exception ex) {
|
73
64
|
super(runtime, rubyClass, ex.getMessage());
|
74
65
|
this.exception = ex;
|
75
66
|
}
|
76
67
|
|
68
|
+
public XmlSyntaxError(Ruby runtime, RubyClass rubyClass, String message, Exception ex) {
|
69
|
+
super(runtime, rubyClass, message);
|
70
|
+
this.exception = ex; this.messageSet = true;
|
71
|
+
}
|
72
|
+
|
73
|
+
public static XmlSyntaxError createXMLSyntaxError(final Ruby runtime) {
|
74
|
+
RubyClass klazz = (RubyClass) runtime.getClassFromPath("Nokogiri::XML::SyntaxError");
|
75
|
+
return new XmlSyntaxError(runtime, klazz);
|
76
|
+
}
|
77
|
+
|
78
|
+
public static XmlSyntaxError createXMLSyntaxError(final Ruby runtime, final Exception ex) {
|
79
|
+
RubyClass klazz = (RubyClass) runtime.getClassFromPath("Nokogiri::XML::SyntaxError");
|
80
|
+
return new XmlSyntaxError(runtime, klazz, ex);
|
81
|
+
}
|
82
|
+
|
83
|
+
public static XmlSyntaxError createHTMLSyntaxError(final Ruby runtime) {
|
84
|
+
RubyClass klazz = (RubyClass) runtime.getClassFromPath("Nokogiri::HTML::SyntaxError");
|
85
|
+
return new XmlSyntaxError(runtime, klazz);
|
86
|
+
}
|
87
|
+
|
88
|
+
public static RubyException createXMLXPathSyntaxError(final Ruby runtime, final String msg, final Exception ex) {
|
89
|
+
RubyClass klazz = (RubyClass) runtime.getClassFromPath("Nokogiri::XML::XPath::SyntaxError");
|
90
|
+
return new XmlSyntaxError(runtime, klazz, msg, ex);
|
91
|
+
}
|
92
|
+
|
77
93
|
public static XmlSyntaxError createWarning(Ruby runtime, SAXParseException e) {
|
78
|
-
XmlSyntaxError xmlSyntaxError =
|
94
|
+
XmlSyntaxError xmlSyntaxError = createXMLSyntaxError(runtime);
|
79
95
|
xmlSyntaxError.setException(runtime, e, 1);
|
80
96
|
return xmlSyntaxError;
|
81
97
|
}
|
82
98
|
|
83
99
|
public static XmlSyntaxError createError(Ruby runtime, SAXParseException e) {
|
84
|
-
XmlSyntaxError xmlSyntaxError =
|
100
|
+
XmlSyntaxError xmlSyntaxError = createXMLSyntaxError(runtime);
|
85
101
|
xmlSyntaxError.setException(runtime, e, 2);
|
86
102
|
return xmlSyntaxError;
|
87
103
|
}
|
88
104
|
|
89
105
|
public static XmlSyntaxError createFatalError(Ruby runtime, SAXParseException e) {
|
90
|
-
XmlSyntaxError xmlSyntaxError =
|
106
|
+
XmlSyntaxError xmlSyntaxError = createXMLSyntaxError(runtime);
|
91
107
|
xmlSyntaxError.setException(runtime, e, 3);
|
92
108
|
return xmlSyntaxError;
|
93
109
|
}
|
94
110
|
|
95
|
-
public static XmlSyntaxError createNokogiriXmlSyntaxError(Ruby runtime) {
|
96
|
-
return (XmlSyntaxError) NokogiriService.XML_SYNTAXERROR_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, "Nokogiri::XML::SyntaxError"));
|
97
|
-
}
|
98
|
-
|
99
111
|
public void setException(Exception exception) {
|
100
112
|
this.exception = exception;
|
101
113
|
}
|
102
114
|
|
103
|
-
public void setException(Ruby runtime,
|
115
|
+
public void setException(Ruby runtime, SAXParseException exception, int level) {
|
104
116
|
this.exception = exception;
|
105
117
|
setInstanceVariable("@level", runtime.newFixnum(level));
|
106
|
-
setInstanceVariable("@line", runtime.newFixnum(
|
107
|
-
setInstanceVariable("@column", runtime.newFixnum(
|
108
|
-
setInstanceVariable("@file", stringOrNil(runtime,
|
109
|
-
}
|
110
|
-
|
111
|
-
public static RubyException createXPathSyntaxError(Ruby runtime, Exception e) {
|
112
|
-
RubyClass klazz = (RubyClass)runtime.getClassFromPath("Nokogiri::XML::XPath::SyntaxError");
|
113
|
-
return new XmlSyntaxError(runtime, klazz, e);
|
118
|
+
setInstanceVariable("@line", runtime.newFixnum(exception.getLineNumber()));
|
119
|
+
setInstanceVariable("@column", runtime.newFixnum(exception.getColumnNumber()));
|
120
|
+
setInstanceVariable("@file", stringOrNil(runtime, exception.getSystemId()));
|
114
121
|
}
|
115
122
|
|
116
123
|
//@Override
|
@@ -119,10 +126,8 @@ public class XmlSyntaxError extends RubyException {
|
|
119
126
|
@Override
|
120
127
|
@JRubyMethod(name = "to_s", compat = CompatVersion.RUBY1_8)
|
121
128
|
public IRubyObject to_s(ThreadContext context) {
|
122
|
-
|
123
|
-
|
124
|
-
else
|
125
|
-
return super.to_s(context);
|
129
|
+
IRubyObject msg = msg(context.runtime);
|
130
|
+
return msg != null ? msg : super.to_s(context);
|
126
131
|
}
|
127
132
|
|
128
133
|
//@Override
|
@@ -130,9 +135,16 @@ public class XmlSyntaxError extends RubyException {
|
|
130
135
|
// to support older version of JRuby, the annotation is commented out
|
131
136
|
@JRubyMethod(name = "to_s", compat = CompatVersion.RUBY1_9)
|
132
137
|
public IRubyObject to_s19(ThreadContext context) {
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
return super.to_s19(context);
|
138
|
+
IRubyObject msg = msg(context.runtime);
|
139
|
+
return msg != null ? msg : super.to_s19(context);
|
137
140
|
}
|
141
|
+
|
142
|
+
private IRubyObject msg(final Ruby runtime) {
|
143
|
+
if (exception != null && exception.getMessage() != null) {
|
144
|
+
if (messageSet) return null;
|
145
|
+
return runtime.newString( exception.getMessage() );
|
146
|
+
}
|
147
|
+
return null;
|
148
|
+
}
|
149
|
+
|
138
150
|
}
|
@@ -32,15 +32,9 @@
|
|
32
32
|
|
33
33
|
package nokogiri;
|
34
34
|
|
35
|
-
import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
|
36
|
-
|
37
|
-
import java.lang.reflect.Constructor;
|
38
|
-
import java.lang.reflect.InvocationTargetException;
|
39
35
|
import java.util.Set;
|
40
36
|
|
41
37
|
import javax.xml.transform.TransformerException;
|
42
|
-
import javax.xml.xpath.XPathExpressionException;
|
43
|
-
import javax.xml.xpath.XPathFactory;
|
44
38
|
|
45
39
|
import nokogiri.internals.NokogiriNamespaceContext;
|
46
40
|
import nokogiri.internals.NokogiriXPathFunctionResolver;
|
@@ -48,18 +42,17 @@ import nokogiri.internals.NokogiriXPathVariableResolver;
|
|
48
42
|
|
49
43
|
import org.jruby.Ruby;
|
50
44
|
import org.jruby.RubyClass;
|
51
|
-
import org.jruby.RubyException;
|
52
45
|
import org.jruby.RubyObject;
|
53
46
|
import org.jruby.anno.JRubyClass;
|
54
47
|
import org.jruby.anno.JRubyMethod;
|
55
48
|
import org.jruby.exceptions.RaiseException;
|
56
49
|
import org.jruby.runtime.ThreadContext;
|
57
50
|
import org.jruby.runtime.builtin.IRubyObject;
|
51
|
+
import org.jruby.util.SafePropertyAccessor;
|
58
52
|
import org.w3c.dom.Node;
|
59
|
-
import org.w3c.dom.NodeList;
|
60
53
|
|
61
54
|
import org.apache.xml.dtm.DTM;
|
62
|
-
import org.apache.
|
55
|
+
import org.apache.xpath.XPath;
|
63
56
|
import org.apache.xpath.XPathContext;
|
64
57
|
import org.apache.xpath.jaxp.JAXPExtensionsProvider;
|
65
58
|
import org.apache.xpath.jaxp.JAXPPrefixResolver;
|
@@ -75,171 +68,206 @@ import org.apache.xpath.objects.XObject;
|
|
75
68
|
*/
|
76
69
|
@JRubyClass(name="Nokogiri::XML::XPathContext")
|
77
70
|
public class XmlXpathContext extends RubyObject {
|
78
|
-
public final static String XPATH_CONTEXT = "CACHCED_XPATH_CONTEXT";
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
super(ruby, rubyClass);
|
89
|
-
functionResolver = NokogiriXPathFunctionResolver.create(ruby.getCurrentContext().nil);
|
90
|
-
variableResolver = NokogiriXPathVariableResolver.create();
|
72
|
+
static {
|
73
|
+
final String DTMManager = "org.apache.xml.dtm.DTMManager";
|
74
|
+
if (SafePropertyAccessor.getProperty(DTMManager) == null) {
|
75
|
+
try { // use patched "org.apache.xml.dtm.ref.DTMManagerDefault"
|
76
|
+
System.setProperty(DTMManager, nokogiri.internals.XalanDTMManagerPatch.class.getName());
|
77
|
+
}
|
78
|
+
catch (SecurityException ex) { /* no-op - will work although might be slower */ }
|
79
|
+
}
|
91
80
|
}
|
92
81
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
}
|
98
|
-
xpathSupport = (XPathContext) doc.getUserData(XPATH_CONTEXT);
|
82
|
+
/**
|
83
|
+
* user-data key for (cached) {@link XPathContext}
|
84
|
+
*/
|
85
|
+
public static final String XPATH_CONTEXT = "CACHED_XPATH_CONTEXT";
|
99
86
|
|
100
|
-
|
101
|
-
JAXPExtensionsProvider jep = getProviderInstance();
|
102
|
-
xpathSupport = new XPathContext(jep);
|
103
|
-
xpathSupport.setVarStack(new JAXPVariableStack(variableResolver));
|
104
|
-
doc.setUserData(XPATH_CONTEXT, xpathSupport, null);
|
105
|
-
}
|
87
|
+
private XmlNode context;
|
106
88
|
|
107
|
-
|
108
|
-
|
109
|
-
prefixResolver = new JAXPPrefixResolver(nsContext);
|
89
|
+
public XmlXpathContext(Ruby runtime, RubyClass klass) {
|
90
|
+
super(runtime, klass);
|
110
91
|
}
|
111
92
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
for (int i = 0; i < constructors.length; i++) {
|
116
|
-
Class[] parameterTypes = constructors[i].getParameterTypes();
|
117
|
-
if (parameterTypes.length == 2) {
|
118
|
-
return (JAXPExtensionsProvider) constructors[i].newInstance(functionResolver, false);
|
119
|
-
} else if (parameterTypes.length == 1) {
|
120
|
-
return (JAXPExtensionsProvider) constructors[i].newInstance(functionResolver);
|
121
|
-
}
|
122
|
-
}
|
123
|
-
return null;
|
93
|
+
public XmlXpathContext(Ruby runtime, RubyClass klass, XmlNode node) {
|
94
|
+
this(runtime, klass);
|
95
|
+
initNode(node);
|
124
96
|
}
|
125
97
|
|
126
|
-
|
127
|
-
|
128
|
-
*
|
129
|
-
* @return a clone of this object
|
130
|
-
*/
|
131
|
-
@Override
|
132
|
-
public Object clone() throws CloneNotSupportedException {
|
133
|
-
return super.clone();
|
98
|
+
private void initNode(XmlNode node) {
|
99
|
+
context = node;
|
134
100
|
}
|
135
101
|
|
136
102
|
@JRubyMethod(name = "new", meta = true)
|
137
|
-
public static IRubyObject rbNew(ThreadContext
|
138
|
-
XmlNode xmlNode = (XmlNode)node;
|
139
|
-
XmlXpathContext xmlXpathContext = (XmlXpathContext) NokogiriService.XML_XPATHCONTEXT_ALLOCATOR.allocate(thread_context.getRuntime(), (RubyClass)klazz);
|
140
|
-
XPathFactory.newInstance().newXPath();
|
103
|
+
public static IRubyObject rbNew(ThreadContext context, IRubyObject klazz, IRubyObject node) {
|
141
104
|
try {
|
142
|
-
|
143
|
-
}
|
144
|
-
|
145
|
-
|
146
|
-
throw thread_context.getRuntime().newRuntimeError(e.getMessage());
|
147
|
-
} catch (InstantiationException e) {
|
148
|
-
throw thread_context.getRuntime().newRuntimeError(e.getMessage());
|
149
|
-
} catch (IllegalAccessException e) {
|
150
|
-
throw thread_context.getRuntime().newRuntimeError(e.getMessage());
|
151
|
-
} catch (InvocationTargetException e) {
|
152
|
-
throw thread_context.getRuntime().newRuntimeError(e.getMessage());
|
105
|
+
return new XmlXpathContext(context.runtime, (RubyClass) klazz, (XmlNode) node);
|
106
|
+
}
|
107
|
+
catch (IllegalArgumentException e) {
|
108
|
+
throw context.getRuntime().newRuntimeError(e.getMessage());
|
153
109
|
}
|
154
|
-
return xmlXpathContext;
|
155
110
|
}
|
156
111
|
|
157
112
|
@JRubyMethod
|
158
|
-
public IRubyObject evaluate(ThreadContext
|
159
|
-
|
160
|
-
String src = (
|
161
|
-
if(!handler.isNil()) {
|
113
|
+
public IRubyObject evaluate(ThreadContext context, IRubyObject expr, IRubyObject handler) {
|
114
|
+
|
115
|
+
String src = expr.convertToString().asJavaString();
|
116
|
+
if (!handler.isNil()) {
|
162
117
|
if (!isContainsPrefix(src)) {
|
118
|
+
StringBuilder replacement = new StringBuilder();
|
163
119
|
Set<String> methodNames = handler.getMetaClass().getMethods().keySet();
|
120
|
+
final String PREFIX = NokogiriNamespaceContext.NOKOGIRI_PREFIX;
|
164
121
|
for (String name : methodNames) {
|
165
|
-
|
122
|
+
replacement.setLength(0);
|
123
|
+
replacement.ensureCapacity(PREFIX.length() + 1 + name.length());
|
124
|
+
replacement.append(PREFIX).append(':').append(name);
|
125
|
+
src = src.replace(name, replacement); // replace(name, NOKOGIRI_PREFIX + ':' + name)
|
166
126
|
}
|
167
127
|
}
|
168
128
|
}
|
169
|
-
|
129
|
+
|
130
|
+
return node_set(context, src, handler);
|
131
|
+
}
|
132
|
+
|
133
|
+
@JRubyMethod
|
134
|
+
public IRubyObject evaluate(ThreadContext context, IRubyObject expr) {
|
135
|
+
return this.evaluate(context, expr, context.getRuntime().getNil());
|
136
|
+
}
|
137
|
+
|
138
|
+
private final NokogiriNamespaceContext nsContext = NokogiriNamespaceContext.create();
|
139
|
+
|
140
|
+
@JRubyMethod
|
141
|
+
public IRubyObject register_ns(IRubyObject prefix, IRubyObject uri) {
|
142
|
+
nsContext.registerNamespace(prefix.asJavaString(), uri.asJavaString());
|
143
|
+
return this;
|
144
|
+
}
|
145
|
+
|
146
|
+
private NokogiriXPathVariableResolver variableResolver; // binds (if any)
|
147
|
+
|
148
|
+
@JRubyMethod
|
149
|
+
public IRubyObject register_variable(IRubyObject name, IRubyObject value) {
|
150
|
+
NokogiriXPathVariableResolver variableResolver = this.variableResolver;
|
151
|
+
if (variableResolver == null) {
|
152
|
+
variableResolver = NokogiriXPathVariableResolver.create();
|
153
|
+
this.variableResolver = variableResolver;
|
154
|
+
}
|
155
|
+
variableResolver.registerVariable(name.asJavaString(), value.asJavaString());
|
156
|
+
return this;
|
170
157
|
}
|
171
158
|
|
172
|
-
|
159
|
+
private IRubyObject node_set(ThreadContext context, String expr, IRubyObject handler) {
|
160
|
+
final NokogiriXPathFunctionResolver fnResolver =
|
161
|
+
handler.isNil() ? null : NokogiriXPathFunctionResolver.create(handler);
|
173
162
|
try {
|
174
|
-
|
175
|
-
}
|
176
|
-
|
177
|
-
|
163
|
+
return tryGetNodeSet(context, expr, fnResolver);
|
164
|
+
}
|
165
|
+
catch (TransformerException ex) {
|
166
|
+
throw new RaiseException(XmlSyntaxError.createXMLXPathSyntaxError(context.runtime, expr, ex)); // Nokogiri::XML::XPath::SyntaxError
|
178
167
|
}
|
179
168
|
}
|
180
169
|
|
181
|
-
private IRubyObject tryGetNodeSet(ThreadContext
|
182
|
-
|
170
|
+
private IRubyObject tryGetNodeSet(ThreadContext context, String expr, NokogiriXPathFunctionResolver fnResolver) throws TransformerException {
|
171
|
+
final Node contextNode = this.context.node;
|
183
172
|
|
184
|
-
|
173
|
+
final JAXPPrefixResolver prefixResolver = new JAXPPrefixResolver(nsContext);
|
174
|
+
XPath xpathInternal = new XPath(expr, null, prefixResolver, XPath.SELECT);
|
185
175
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
return
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
176
|
+
// We always need to have a ContextNode with Xalan XPath implementation
|
177
|
+
// To allow simple expression evaluation like 1+1 we are setting
|
178
|
+
// dummy Document as Context Node
|
179
|
+
final XObject xobj;
|
180
|
+
if ( contextNode == null )
|
181
|
+
xobj = xpathInternal.execute(getXPathContext(fnResolver), DTM.NULL, prefixResolver);
|
182
|
+
else
|
183
|
+
xobj = xpathInternal.execute(getXPathContext(fnResolver), contextNode, prefixResolver);
|
184
|
+
|
185
|
+
switch (xobj.getType()) {
|
186
|
+
case XObject.CLASS_BOOLEAN : return context.getRuntime().newBoolean(xobj.bool());
|
187
|
+
case XObject.CLASS_NUMBER : return context.getRuntime().newFloat(xobj.num());
|
188
|
+
case XObject.CLASS_NODESET :
|
189
|
+
XmlNodeSet xmlNodeSet = XmlNodeSet.create(context.getRuntime());
|
190
|
+
xmlNodeSet.setNodeList(xobj.nodelist());
|
191
|
+
xmlNodeSet.initialize(context.getRuntime(), this.context);
|
192
|
+
return xmlNodeSet;
|
193
|
+
default : return context.getRuntime().newString(xobj.str());
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
private XPathContext getXPathContext(final NokogiriXPathFunctionResolver fnResolver) {
|
198
|
+
Node doc = context.getNode().getOwnerDocument();
|
199
|
+
if (doc == null) doc = context.getNode();
|
200
|
+
|
201
|
+
XPathContext xpathContext = (XPathContext) doc.getUserData(XPATH_CONTEXT);
|
202
|
+
|
203
|
+
if ( xpathContext == null ) {
|
204
|
+
xpathContext = newXPathContext(fnResolver);
|
205
|
+
if ( variableResolver == null ) {
|
206
|
+
// NOTE: only caching without variables - could be improved by more sophisticated caching
|
207
|
+
doc.setUserData(XPATH_CONTEXT, xpathContext, null);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
else {
|
211
|
+
Object owner = xpathContext.getOwnerObject();
|
212
|
+
if ( ( owner == null && fnResolver == null ) ||
|
213
|
+
( owner instanceof JAXPExtensionsProvider && ((JAXPExtensionsProvider) owner).hasSameResolver(fnResolver) ) ) {
|
214
|
+
// can be re-used assuming it has the same variable-stack (for now only cached if no variables)
|
215
|
+
if ( variableResolver == null ) return xpathContext;
|
216
|
+
}
|
217
|
+
xpathContext = newXPathContext(fnResolver); // otherwise we can not use the cached xpath-context
|
218
|
+
}
|
219
|
+
|
220
|
+
if ( variableResolver != null ) {
|
221
|
+
xpathContext.setVarStack(new JAXPVariableStack(variableResolver));
|
215
222
|
}
|
223
|
+
|
224
|
+
return xpathContext;
|
216
225
|
}
|
217
226
|
|
218
|
-
private
|
219
|
-
|
220
|
-
|
221
|
-
|
227
|
+
private static XPathContext newXPathContext(final NokogiriXPathFunctionResolver functionResolver) {
|
228
|
+
if ( functionResolver == null ) return new XPathContext(false);
|
229
|
+
return new XPathContext(new JAXPExtensionsProvider(functionResolver), false);
|
230
|
+
}
|
231
|
+
|
232
|
+
private boolean isContainsPrefix(final String str) {
|
233
|
+
final StringBuilder prefix_ = new StringBuilder();
|
234
|
+
for ( String prefix : nsContext.getAllPrefixes() ) {
|
235
|
+
prefix_.setLength(0);
|
236
|
+
prefix_.ensureCapacity(prefix.length() + 1);
|
237
|
+
prefix_.append(prefix).append(':');
|
238
|
+
if ( str.contains(prefix_) ) { // prefix + ':'
|
222
239
|
return true;
|
223
240
|
}
|
224
241
|
}
|
225
242
|
return false;
|
226
243
|
}
|
227
244
|
|
245
|
+
private static final class JAXPExtensionsProvider extends org.apache.xpath.jaxp.JAXPExtensionsProvider {
|
228
246
|
|
229
|
-
|
230
|
-
public IRubyObject evaluate(ThreadContext context, IRubyObject expr) {
|
231
|
-
return this.evaluate(context, expr, context.getRuntime().getNil());
|
232
|
-
}
|
247
|
+
final NokogiriXPathFunctionResolver resolver;
|
233
248
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
249
|
+
JAXPExtensionsProvider(NokogiriXPathFunctionResolver resolver) {
|
250
|
+
super(resolver, false);
|
251
|
+
this.resolver = resolver;
|
252
|
+
}
|
253
|
+
|
254
|
+
//@Override
|
255
|
+
//public boolean equals(Object obj) {
|
256
|
+
// if (obj instanceof JAXPExtensionsProvider) {
|
257
|
+
// return hasSameResolver(((JAXPExtensionsProvider) obj).resolver);
|
258
|
+
// }
|
259
|
+
// return false;
|
260
|
+
//}
|
261
|
+
|
262
|
+
final boolean hasSameResolver(final NokogiriXPathFunctionResolver resolver) {
|
263
|
+
return resolver == this.resolver || resolver != null && (
|
264
|
+
resolver.getHandler() == null ? this.resolver.getHandler() == null : (
|
265
|
+
resolver.getHandler() == this.resolver.getHandler()
|
266
|
+
// resolver.getHandler().eql( this.resolver.getHandler() )
|
267
|
+
)
|
268
|
+
);
|
269
|
+
}
|
239
270
|
|
240
|
-
@JRubyMethod
|
241
|
-
public IRubyObject register_variable(ThreadContext context, IRubyObject name, IRubyObject value) {
|
242
|
-
variableResolver.registerVariable((String)name.toJava(String.class), (String)value.toJava(String.class));
|
243
|
-
return this;
|
244
271
|
}
|
272
|
+
|
245
273
|
}
|