nokogiri 1.5.2-java → 1.5.3-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (70) hide show
  1. data/CHANGELOG.ja.rdoc +35 -0
  2. data/CHANGELOG.rdoc +37 -2
  3. data/Manifest.txt +11 -3
  4. data/README.rdoc +1 -1
  5. data/ROADMAP.md +86 -0
  6. data/{nokogiri_help_responses.md → STANDARD_RESPONSES.md} +11 -4
  7. data/Y_U_NO_GEMSPEC.md +155 -0
  8. data/build_all +58 -0
  9. data/ext/java/nokogiri/HtmlDocument.java +10 -1
  10. data/ext/java/nokogiri/XmlAttr.java +11 -1
  11. data/ext/java/nokogiri/XmlDocument.java +4 -0
  12. data/ext/java/nokogiri/XmlNamespace.java +25 -0
  13. data/ext/java/nokogiri/XmlNode.java +6 -6
  14. data/ext/java/nokogiri/XmlReader.java +19 -4
  15. data/ext/java/nokogiri/XmlSaxPushParser.java +88 -57
  16. data/ext/java/nokogiri/XmlSyntaxError.java +15 -3
  17. data/ext/java/nokogiri/XmlXpathContext.java +3 -3
  18. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +2 -1
  19. data/ext/java/nokogiri/internals/NokogiriHelpers.java +89 -1
  20. data/ext/java/nokogiri/internals/ParserContext.java +23 -2
  21. data/ext/java/nokogiri/internals/SaveContextVisitor.java +18 -1
  22. data/ext/java/nokogiri/internals/XmlDomParserContext.java +2 -3
  23. data/ext/nokogiri/extconf.rb +1 -1
  24. data/ext/nokogiri/xml_io.c +1 -1
  25. data/ext/nokogiri/xml_namespace.c +0 -6
  26. data/ext/nokogiri/xml_node.c +11 -11
  27. data/ext/nokogiri/xml_node_set.c +1 -1
  28. data/ext/nokogiri/xml_xpath_context.c +20 -16
  29. data/ext/nokogiri/xml_xpath_context.h +1 -0
  30. data/ext/nokogiri/xslt_stylesheet.c +7 -64
  31. data/lib/nokogiri/css/node.rb +3 -0
  32. data/lib/nokogiri/css/parser.rb +244 -203
  33. data/lib/nokogiri/css/parser.y +20 -2
  34. data/lib/nokogiri/css/xpath_visitor.rb +2 -2
  35. data/lib/nokogiri/html/document.rb +2 -1
  36. data/lib/nokogiri/html/element_description_defaults.rb +1 -1
  37. data/lib/nokogiri/nokogiri.jar +0 -0
  38. data/lib/nokogiri/version.rb +1 -1
  39. data/lib/nokogiri/xml/document.rb +1 -1
  40. data/lib/nokogiri/xml/parse_options.rb +2 -2
  41. data/lib/nokogiri/xml/sax/document.rb +1 -1
  42. data/lib/nokogiri/xml/sax/parser.rb +1 -1
  43. data/lib/nokogiri/xslt.rb +1 -1
  44. data/test/css/test_parser.rb +38 -0
  45. data/test/files/to_be_xincluded.xml +2 -0
  46. data/test/files/xinclude.xml +4 -0
  47. data/test/helper.rb +18 -45
  48. data/test/html/sax/test_parser.rb +5 -3
  49. data/test/html/sax/test_parser_context.rb +8 -10
  50. data/test/html/test_document.rb +19 -5
  51. data/test/html/test_node.rb +2 -4
  52. data/test/test_reader.rb +63 -0
  53. data/test/test_xslt_transforms.rb +3 -1
  54. data/test/xml/sax/test_parser_context.rb +10 -17
  55. data/test/xml/sax/test_push_parser.rb +1 -0
  56. data/test/xml/test_attr.rb +5 -6
  57. data/test/xml/test_builder.rb +5 -6
  58. data/test/xml/test_cdata.rb +1 -3
  59. data/test/xml/test_document.rb +11 -14
  60. data/test/xml/test_document_encoding.rb +3 -1
  61. data/test/xml/test_document_fragment.rb +27 -8
  62. data/test/xml/test_node.rb +21 -0
  63. data/test/xml/test_node_set.rb +2 -2
  64. data/test/xml/test_text.rb +1 -3
  65. data/test/xml/test_unparented_node.rb +2 -2
  66. data/test/xml/test_xpath.rb +15 -6
  67. data/test/xslt/test_custom_functions.rb +35 -0
  68. data/test_all +84 -0
  69. metadata +13 -8
  70. data/ext/java/nokogiri/internals/PushInputStream.java +0 -411
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * (The MIT License)
3
3
  *
4
- * Copyright (c) 2008 - 2011:
4
+ * Copyright (c) 2008 - 2012:
5
5
  *
6
6
  * * {Aaron Patterson}[http://tenderlovemaking.com]
7
7
  * * {Mike Dalessio}[http://mike.daless.io]
@@ -135,6 +135,7 @@ public class HtmlDomParserContext extends XmlDomParserContext {
135
135
  }
136
136
  }
137
137
  htmlDocument.setEncoding(ruby_encoding);
138
+ htmlDocument.setParsedEncoding(java_encoding);
138
139
  return htmlDocument;
139
140
  }
140
141
 
@@ -34,6 +34,8 @@ package nokogiri.internals;
34
34
 
35
35
  import java.io.File;
36
36
  import java.io.UnsupportedEncodingException;
37
+ import java.lang.reflect.InvocationTargetException;
38
+ import java.lang.reflect.Method;
37
39
  import java.nio.ByteBuffer;
38
40
  import java.nio.CharBuffer;
39
41
  import java.nio.charset.CharacterCodingException;
@@ -42,6 +44,8 @@ import java.nio.charset.CharsetDecoder;
42
44
  import java.nio.charset.CharsetEncoder;
43
45
  import java.util.ArrayList;
44
46
  import java.util.List;
47
+ import java.util.Set;
48
+ import java.util.SortedMap;
45
49
  import java.util.regex.Matcher;
46
50
  import java.util.regex.Pattern;
47
51
 
@@ -255,6 +259,7 @@ public class NokogiriHelpers {
255
259
  * this for us.
256
260
  */
257
261
  public static String rubyStringToString(IRubyObject str) {
262
+ if (str.isNil()) return null;
258
263
  //return rubyStringToString(str.convertToString());
259
264
  return toJavaString(str.convertToString());
260
265
  }
@@ -656,13 +661,29 @@ public class NokogiriHelpers {
656
661
  return n;
657
662
  }
658
663
 
659
- public static String guessEncoding(Ruby ruby) {
664
+ public static String getValidEncoding(Ruby runtime, IRubyObject encoding) {
665
+ if (encoding.isNil()) {
666
+ return guessEncoding();
667
+ } else {
668
+ return ignoreInvalidEncoding(runtime, encoding);
669
+ }
670
+ }
671
+
672
+ private static String guessEncoding() {
660
673
  String name = null;
661
674
  if (name == null) name = System.getProperty("file.encoding");
662
675
  if (name == null) name = "UTF-8";
663
676
  return name;
664
677
  }
665
678
 
679
+ private static Set<String> charsetNames = ((SortedMap<String, Charset>)Charset.availableCharsets()).keySet();
680
+
681
+ private static String ignoreInvalidEncoding(Ruby runtime, IRubyObject encoding) {
682
+ String givenEncoding = rubyStringToString(encoding);
683
+ if (charsetNames.contains(givenEncoding)) return givenEncoding;
684
+ else return guessEncoding();
685
+ }
686
+
666
687
  public static String adjustSystemIdIfNecessary(String currentDir, String scriptFileName, String baseURI, String systemId) {
667
688
  if (systemId == null) return systemId;
668
689
  File file = new File(systemId);
@@ -709,4 +730,71 @@ public class NokogiriHelpers {
709
730
  return bytes;
710
731
  }
711
732
 
733
+ public static String convertEncodingByNKFIfNecessary(Ruby runtime, XmlDocument doc, String thing) {
734
+ if (!(doc instanceof HtmlDocument)) return thing;
735
+ String parsed_encoding = ((HtmlDocument)doc).getPraedEncoding();
736
+ if (parsed_encoding == null) return thing;
737
+ String ruby_encoding = rubyStringToString(doc.getEncoding());
738
+ if (ruby_encoding == null) return thing;
739
+ if (Charset.forName(parsed_encoding).compareTo(Charset.forName(ruby_encoding)) == 0) {
740
+ return thing;
741
+ } else {
742
+ return NokogiriHelpers.nkf(runtime, ruby_encoding, thing);
743
+ }
744
+
745
+ }
746
+
747
+ // This method is used from HTML documents. HTML meta tag with encoding specification
748
+ // might appear after non-ascii characters are used. For example, a title tag before
749
+ // a meta tag. In such a case, Xerces encodes characters in UTF-8 without seeing meta tag.
750
+ // Nokogiri uses NKF library to convert characters correct encoding. This means the method
751
+ // works only for JIS/Shift_JIS/EUC-JP.
752
+ public static String nkf(Ruby runtime, String ruby_encoding, String thing) {
753
+ StringBuffer sb = new StringBuffer("-");
754
+ Charset that = Charset.forName(ruby_encoding);
755
+ if (NokogiriHelpers.shift_jis.compareTo(that) == 0) {
756
+ sb.append("S");
757
+ } else if (NokogiriHelpers.jis.compareTo(that) == 0) {
758
+ sb.append("J");
759
+ } else if (NokogiriHelpers.euc_jp.compareTo(that) == 0) {
760
+ sb.append("E");
761
+ } else {
762
+ // should not come here. should be treated before this method.
763
+ sb.append("W");
764
+ }
765
+ sb.append("w");
766
+ Class nkfClass = null;
767
+ try {
768
+ // JRuby 1.7 and later
769
+ nkfClass = runtime.getClassLoader().loadClass("org.jruby.ext.nkf.RubyNKF");
770
+ } catch (ClassNotFoundException e1) {
771
+ try {
772
+ // Before JRuby 1.7
773
+ nkfClass = runtime.getClassLoader().loadClass("org.jruby.RubyNKF");
774
+ } catch (ClassNotFoundException e2) {
775
+ return thing;
776
+ }
777
+ }
778
+ Method nkf_method;
779
+ try {
780
+ nkf_method = nkfClass.getMethod("nkf", ThreadContext.class, IRubyObject.class, IRubyObject.class, IRubyObject.class);
781
+ RubyString r_str =
782
+ (RubyString)nkf_method.invoke(null, runtime.getCurrentContext(), null, runtime.newString(new String(sb)), runtime.newString(thing));
783
+ return NokogiriHelpers.rubyStringToString(r_str);
784
+ } catch (SecurityException e) {
785
+ return thing;
786
+ } catch (NoSuchMethodException e) {
787
+ return thing;
788
+ } catch (IllegalArgumentException e) {
789
+ return thing;
790
+ } catch (IllegalAccessException e) {
791
+ return thing;
792
+ } catch (InvocationTargetException e) {
793
+ return thing;
794
+ }
795
+ }
796
+
797
+ private static Charset shift_jis = Charset.forName("Shift_JIS");
798
+ private static Charset jis = Charset.forName("ISO-2022-JP");
799
+ private static Charset euc_jp = Charset.forName("EUC-JP");
712
800
  }
@@ -40,6 +40,9 @@ import java.io.ByteArrayInputStream;
40
40
  import java.io.File;
41
41
  import java.io.IOException;
42
42
  import java.io.InputStream;
43
+ import java.io.StringReader;
44
+ import java.nio.charset.Charset;
45
+ import java.nio.charset.UnsupportedCharsetException;
43
46
 
44
47
  import org.jruby.Ruby;
45
48
  import org.jruby.RubyClass;
@@ -159,9 +162,27 @@ public class ParserContext extends RubyObject {
159
162
  }
160
163
  }
161
164
  if (stringData != null) {
165
+ String encName = null;
166
+ if (stringData.encoding(context) != null) {
167
+ encName = stringData.encoding(context).toString();
168
+ }
169
+ Charset charset = null;
170
+ if (encName != null) {
171
+ try {
172
+ charset = Charset.forName(encName);
173
+ } catch (UnsupportedCharsetException e) {
174
+ // do nothing;
175
+ }
176
+ }
162
177
  ByteList bytes = stringData.getByteList();
163
- stringDataSize = bytes.length() - bytes.begin();
164
- source = new InputSource(new ByteArrayInputStream(bytes.unsafeBytes(), bytes.begin(), bytes.length()));
178
+ if (charset != null) {
179
+ StringReader reader = new StringReader(new String(bytes.unsafeBytes(), bytes.begin(), bytes.length(), charset));
180
+ source = new InputSource(reader);
181
+ source.setEncoding(charset.name());
182
+ } else {
183
+ stringDataSize = bytes.length() - bytes.begin();
184
+ source = new InputSource(new ByteArrayInputStream(bytes.unsafeBytes(), bytes.begin(), bytes.length()));
185
+ }
165
186
  }
166
187
  }
167
188
 
@@ -45,6 +45,8 @@ import java.util.Deque;
45
45
  import java.util.Iterator;
46
46
  import java.util.List;
47
47
  import java.util.Stack;
48
+ import java.util.regex.Matcher;
49
+ import java.util.regex.Pattern;
48
50
 
49
51
  import org.cyberneko.html.HTMLElements;
50
52
  import org.w3c.dom.Attr;
@@ -252,12 +254,27 @@ public class SaveContextVisitor {
252
254
  if (!asHtml || !isHtmlBooleanAttr(name)) {
253
255
  buffer.append("=");
254
256
  buffer.append("\"");
255
- buffer.append(serializeAttrTextContent(attr.getValue(), htmlDoc));
257
+ String value = replaceCharsetIfNecessary(attr);
258
+ buffer.append(serializeAttrTextContent(value, htmlDoc));
256
259
  buffer.append("\"");
257
260
  }
258
261
  return true;
259
262
  }
260
263
 
264
+ private static Pattern p =
265
+ Pattern.compile("charset(()|\\s+)=(()|\\s+)(\\w|\\_|\\.|\\-)+", Pattern.CASE_INSENSITIVE);
266
+
267
+ private String replaceCharsetIfNecessary(Attr attr) {
268
+ String value = attr.getValue();
269
+ if (encoding == null) return value; // unable to replace in any case
270
+ if (!"content".equals(attr.getName().toLowerCase())) return value; // must be content attr
271
+ if (!"meta".equals(attr.getOwnerElement().getNodeName().toLowerCase())) return value;
272
+ Matcher m = p.matcher(value);
273
+ if (!m.find()) return value;
274
+ if (value.contains(encoding)) return value; // no need to replace
275
+ return value.replace(m.group(), "charset=" + encoding);
276
+ }
277
+
261
278
  public static final String[] HTML_BOOLEAN_ATTRS = {
262
279
  "checked", "compact", "declare", "defer", "disabled", "ismap",
263
280
  "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * (The MIT License)
3
3
  *
4
- * Copyright (c) 2008 - 2011:
4
+ * Copyright (c) 2008 - 2012:
5
5
  *
6
6
  * * {Aaron Patterson}[http://tenderlovemaking.com]
7
7
  * * {Mike Dalessio}[http://mike.daless.io]
@@ -33,7 +33,6 @@
33
33
  package nokogiri.internals;
34
34
 
35
35
  import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
36
- import static nokogiri.internals.NokogiriHelpers.rubyStringToString;
37
36
  import java.io.ByteArrayInputStream;
38
37
  import java.io.IOException;
39
38
  import java.util.ArrayList;
@@ -88,7 +87,7 @@ public class XmlDomParserContext extends ParserContext {
88
87
  public XmlDomParserContext(Ruby runtime, IRubyObject encoding, IRubyObject options) {
89
88
  super(runtime);
90
89
  this.options = new ParserContext.Options((Long)options.toJava(Long.class));
91
- this.java_encoding = encoding.isNil() ? NokogiriHelpers.guessEncoding(runtime) : rubyStringToString(encoding);
90
+ java_encoding = NokogiriHelpers.getValidEncoding(runtime, encoding);
92
91
  ruby_encoding = encoding;
93
92
  initErrorHandler();
94
93
  initParser(runtime);
@@ -104,7 +104,7 @@ pkg_config('libxslt') if RUBY_PLATFORM =~ /mingw/
104
104
  asplode "libxml2" unless find_header('libxml/parser.h')
105
105
  asplode "libxslt" unless find_header('libxslt/xslt.h')
106
106
  asplode "libexslt" unless find_header('libexslt/exslt.h')
107
- asplode "libiconv" unless have_func('iconv_open', 'iconv.h') or have_library('iconv', 'iconv_open', 'iconv.h')
107
+ asplode "libiconv" unless have_func('iconv_open', 'iconv.h') or have_library('iconv', 'iconv_open', 'iconv.h') or find_library('iconv', 'iconv_open', 'iconv.h')
108
108
  asplode "libxml2" unless find_library("#{lib_prefix}xml2", 'xmlParseDoc')
109
109
  asplode "libxslt" unless find_library("#{lib_prefix}xslt", 'xsltParseStylesheetDoc')
110
110
  asplode "libexslt" unless find_library("#{lib_prefix}exslt", 'exsltFuncRegister')
@@ -25,7 +25,7 @@ int io_read_callback(void * ctx, char * buffer, int len) {
25
25
  safe_len = str_len > (size_t)len ? (size_t)len : str_len;
26
26
  memcpy(buffer, StringValuePtr(string), safe_len);
27
27
 
28
- return safe_len;
28
+ return (int)safe_len;
29
29
  }
30
30
 
31
31
  VALUE write_check(VALUE *args) {
@@ -11,13 +11,10 @@ VALUE cNokogiriXmlNamespace ;
11
11
  static VALUE prefix(VALUE self)
12
12
  {
13
13
  xmlNsPtr ns;
14
- xmlDocPtr doc;
15
14
 
16
15
  Data_Get_Struct(self, xmlNs, ns);
17
16
  if(!ns->prefix) return Qnil;
18
17
 
19
- Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
20
-
21
18
  return NOKOGIRI_STR_NEW2(ns->prefix);
22
19
  }
23
20
 
@@ -30,13 +27,10 @@ static VALUE prefix(VALUE self)
30
27
  static VALUE href(VALUE self)
31
28
  {
32
29
  xmlNsPtr ns;
33
- xmlDocPtr doc;
34
30
 
35
31
  Data_Get_Struct(self, xmlNs, ns);
36
32
  if(!ns->href) return Qnil;
37
33
 
38
- Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
39
-
40
34
  return NOKOGIRI_STR_NEW2(ns->href);
41
35
  }
42
36
 
@@ -1219,7 +1219,7 @@ static VALUE process_xincludes(VALUE self, VALUE options)
1219
1219
  /* TODO: DOCUMENT ME */
1220
1220
  static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1221
1221
  {
1222
- xmlNodePtr node, list, child_iter, tmp, node_children, doc_children;
1222
+ xmlNodePtr node, list = 0, child_iter, node_children, doc_children;
1223
1223
  xmlNodeSetPtr set;
1224
1224
  xmlParserErrors error;
1225
1225
  VALUE doc, err;
@@ -1257,8 +1257,8 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1257
1257
  * is because if there were errors, it's possible for the child pointers
1258
1258
  * to be manipulated. */
1259
1259
  if (error != XML_ERR_OK) {
1260
- node->doc->children = doc_children;
1261
- node->children = node_children;
1260
+ node->doc->children = doc_children;
1261
+ node->children = node_children;
1262
1262
  }
1263
1263
 
1264
1264
  /* make sure parent/child pointers are coherent so an unlink will work
@@ -1266,9 +1266,9 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1266
1266
  */
1267
1267
  child_iter = node->doc->children ;
1268
1268
  while (child_iter) {
1269
- if (child_iter->parent != (xmlNodePtr)node->doc)
1270
- child_iter->parent = (xmlNodePtr)node->doc;
1271
- child_iter = child_iter->next;
1269
+ if (child_iter->parent != (xmlNodePtr)node->doc)
1270
+ child_iter->parent = (xmlNodePtr)node->doc;
1271
+ child_iter = child_iter->next;
1272
1272
  }
1273
1273
 
1274
1274
  #ifndef HTML_PARSE_NOIMPLIED
@@ -1285,12 +1285,12 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1285
1285
  * https://bugzilla.gnome.org/show_bug.cgi?id=668155
1286
1286
  */
1287
1287
  if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
1288
- tmp = node;
1289
- while (tmp->parent)
1290
- tmp = tmp->parent;
1288
+ child_iter = node;
1289
+ while (child_iter->parent)
1290
+ child_iter = child_iter->parent;
1291
1291
 
1292
- if (tmp->type == XML_DOCUMENT_FRAG_NODE)
1293
- node->doc->children = NULL;
1292
+ if (child_iter->type == XML_DOCUMENT_FRAG_NODE)
1293
+ node->doc->children = NULL;
1294
1294
  }
1295
1295
 
1296
1296
  /* FIXME: This probably needs to handle more constants... */
@@ -427,7 +427,7 @@ VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set, VALUE document)
427
427
  rb_funcall(document, decorate, 1, new_set);
428
428
  }
429
429
 
430
- if (node_set->nodeTab) {
430
+ if (node_set && node_set->nodeTab) {
431
431
  for (i = 0; i < node_set->nodeNr; i++) {
432
432
  cur = node_set->nodeTab[i];
433
433
  if (cur && cur->type == XML_NAMESPACE_DECL) {
@@ -49,26 +49,19 @@ static VALUE register_variable(VALUE self, VALUE name, VALUE value)
49
49
  return self;
50
50
  }
51
51
 
52
- static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
52
+ void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, const char* function_name)
53
53
  {
54
- VALUE xpath_handler = Qnil;
55
- VALUE result;
54
+ int i;
55
+ VALUE result, doc;
56
56
  VALUE *argv;
57
- VALUE doc;
58
57
  VALUE node_set = Qnil;
59
58
  xmlNodeSetPtr xml_node_set = NULL;
60
59
  xmlXPathObjectPtr obj;
61
- int i;
62
60
  nokogiriNodeSetTuple *node_set_tuple;
63
61
 
64
- assert(ctx);
65
- assert(ctx->context);
66
- assert(ctx->context->userData);
67
62
  assert(ctx->context->doc);
68
63
  assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));
69
64
 
70
- xpath_handler = (VALUE)(ctx->context->userData);
71
-
72
65
  argv = (VALUE *)calloc((size_t)nargs, sizeof(VALUE));
73
66
  for (i = 0 ; i < nargs ; ++i) {
74
67
  rb_gc_register_address(&argv[i]);
@@ -100,12 +93,7 @@ static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
100
93
  } while(i-- > 0);
101
94
  }
102
95
 
103
- result = rb_funcall2(
104
- xpath_handler,
105
- rb_intern((const char *)ctx->context->function),
106
- nargs,
107
- argv
108
- );
96
+ result = rb_funcall2(handler, rb_intern((const char*)function_name), nargs, argv);
109
97
 
110
98
  for (i = 0 ; i < nargs ; ++i) {
111
99
  rb_gc_unregister_address(&argv[i]);
@@ -156,6 +144,22 @@ static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
156
144
  }
157
145
  }
158
146
 
147
+ static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
148
+ {
149
+ VALUE handler = Qnil;
150
+ const char *function = NULL ;
151
+
152
+ assert(ctx);
153
+ assert(ctx->context);
154
+ assert(ctx->context->userData);
155
+ assert(ctx->context->function);
156
+
157
+ handler = (VALUE)(ctx->context->userData);
158
+ function = (const char*)(ctx->context->function);
159
+
160
+ Nokogiri_marshal_xpath_funcall_and_return_values(ctx, nargs, handler, function);
161
+ }
162
+
159
163
  static xmlXPathFunction lookup( void *ctx,
160
164
  const xmlChar * name,
161
165
  const xmlChar* ns_uri )
@@ -4,6 +4,7 @@
4
4
  #include <nokogiri.h>
5
5
 
6
6
  void init_xml_xpath_context();
7
+ void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, const char* function_name) ;
7
8
 
8
9
  extern VALUE cNokogiriXmlXpathContext;
9
10
  #endif
@@ -168,74 +168,17 @@ static VALUE transform(int argc, VALUE* argv, VALUE self)
168
168
 
169
169
  static void method_caller(xmlXPathParserContextPtr ctxt, int nargs)
170
170
  {
171
- const xmlChar * function;
172
- const xmlChar * functionURI;
173
- size_t i, count;
174
-
171
+ VALUE handler;
172
+ const char *function_name;
175
173
  xsltTransformContextPtr transform;
176
- xmlXPathObjectPtr xpath;
177
- VALUE obj;
178
- VALUE *args;
179
- VALUE result;
174
+ const xmlChar *functionURI;
180
175
 
181
176
  transform = xsltXPathGetTransformContext(ctxt);
182
-
183
- function = ctxt->context->function;
184
177
  functionURI = ctxt->context->functionURI;
185
- obj = (VALUE)xsltGetExtData(transform, functionURI);
186
-
187
- count = (size_t)ctxt->valueNr;
188
- args = calloc(count, sizeof(VALUE *));
189
-
190
- for(i = 0; i < count; i++) {
191
- VALUE thing;
192
-
193
- xpath = valuePop(ctxt);
194
- switch(xpath->type) {
195
- case XPATH_STRING:
196
- thing = NOKOGIRI_STR_NEW2(xpath->stringval);
197
- break;
198
- case XPATH_NODESET:
199
- if(NULL == xpath->nodesetval) {
200
- thing = Nokogiri_wrap_xml_node_set(
201
- xmlXPathNodeSetCreate(NULL),
202
- DOC_RUBY_OBJECT(ctxt->context->doc));
203
- } else {
204
- thing = Nokogiri_wrap_xml_node_set(xpath->nodesetval,
205
- DOC_RUBY_OBJECT(ctxt->context->doc));
206
- }
207
- break;
208
- default:
209
- rb_raise(rb_eRuntimeError, "do not handle type: %d", xpath->type);
210
- }
211
- args[i] = thing;
212
- xmlFree(xpath);
213
- }
214
- result = rb_funcall3(obj, rb_intern((const char *)function), (int)count, args);
215
- free(args);
216
- switch(TYPE(result)) {
217
- case T_FLOAT:
218
- case T_BIGNUM:
219
- case T_FIXNUM:
220
- xmlXPathReturnNumber(ctxt, NUM2DBL(result));
221
- break;
222
- case T_STRING:
223
- xmlXPathReturnString(
224
- ctxt,
225
- xmlStrdup((xmlChar *)StringValuePtr(result))
226
- );
227
- break;
228
- case T_TRUE:
229
- xmlXPathReturnTrue(ctxt);
230
- break;
231
- case T_FALSE:
232
- xmlXPathReturnFalse(ctxt);
233
- break;
234
- case T_NIL:
235
- break;
236
- default:
237
- rb_raise(rb_eRuntimeError, "Invalid return type");
238
- }
178
+ handler = (VALUE)xsltGetExtData(transform, functionURI);
179
+ function_name = (const char*)(ctxt->context->function);
180
+
181
+ Nokogiri_marshal_xpath_funcall_and_return_values(ctxt, nargs, handler, (const char*)function_name);
239
182
  }
240
183
 
241
184
  static void * initFunc(xsltTransformContextPtr ctxt, const xmlChar *uri)