nokogiri 1.5.0.beta.2 → 1.5.0.beta.3

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 (107) hide show
  1. data/CHANGELOG.ja.rdoc +63 -0
  2. data/CHANGELOG.rdoc +44 -1
  3. data/Manifest.txt +3 -3
  4. data/README.ja.rdoc +4 -4
  5. data/README.rdoc +4 -4
  6. data/Rakefile +3 -0
  7. data/bin/nokogiri +6 -1
  8. data/ext/java/nokogiri/EncodingHandler.java +32 -0
  9. data/ext/java/nokogiri/HtmlDocument.java +36 -0
  10. data/ext/java/nokogiri/HtmlElementDescription.java +34 -0
  11. data/ext/java/nokogiri/HtmlEntityLookup.java +34 -0
  12. data/ext/java/nokogiri/HtmlSaxParserContext.java +41 -3
  13. data/ext/java/nokogiri/NokogiriService.java +109 -13
  14. data/ext/java/nokogiri/XmlAttr.java +40 -4
  15. data/ext/java/nokogiri/XmlAttributeDecl.java +32 -0
  16. data/ext/java/nokogiri/XmlCdata.java +41 -2
  17. data/ext/java/nokogiri/XmlComment.java +38 -1
  18. data/ext/java/nokogiri/XmlDocument.java +56 -11
  19. data/ext/java/nokogiri/XmlDocumentFragment.java +39 -30
  20. data/ext/java/nokogiri/XmlDtd.java +37 -0
  21. data/ext/java/nokogiri/XmlElement.java +51 -2
  22. data/ext/java/nokogiri/XmlElementContent.java +32 -0
  23. data/ext/java/nokogiri/XmlElementDecl.java +32 -0
  24. data/ext/java/nokogiri/XmlEntityDecl.java +32 -0
  25. data/ext/java/nokogiri/XmlEntityReference.java +35 -2
  26. data/ext/java/nokogiri/XmlNamespace.java +55 -5
  27. data/ext/java/nokogiri/XmlNode.java +129 -136
  28. data/ext/java/nokogiri/XmlNodeSet.java +36 -0
  29. data/ext/java/nokogiri/XmlProcessingInstruction.java +34 -1
  30. data/ext/java/nokogiri/XmlReader.java +36 -0
  31. data/ext/java/nokogiri/XmlRelaxng.java +34 -1
  32. data/ext/java/nokogiri/XmlSaxParserContext.java +52 -7
  33. data/ext/java/nokogiri/XmlSaxPushParser.java +36 -0
  34. data/ext/java/nokogiri/XmlSchema.java +34 -1
  35. data/ext/java/nokogiri/XmlSyntaxError.java +48 -18
  36. data/ext/java/nokogiri/XmlText.java +45 -6
  37. data/ext/java/nokogiri/XmlXpathContext.java +45 -0
  38. data/ext/java/nokogiri/XsltStylesheet.java +58 -3
  39. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +50 -26
  40. data/ext/java/nokogiri/internals/NokogiriDocumentCache.java +35 -1
  41. data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +51 -13
  42. data/ext/java/nokogiri/internals/NokogiriHandler.java +70 -21
  43. data/ext/java/nokogiri/internals/NokogiriHelpers.java +95 -38
  44. data/ext/java/nokogiri/internals/NokogiriNamespaceCache.java +37 -3
  45. data/ext/java/nokogiri/internals/NokogiriNamespaceContext.java +39 -1
  46. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +43 -7
  47. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +77 -10
  48. data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +49 -20
  49. data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +34 -2
  50. data/ext/java/nokogiri/internals/NokogiriXPathFunctionResolver.java +34 -1
  51. data/ext/java/nokogiri/internals/ParserContext.java +32 -0
  52. data/ext/java/nokogiri/internals/PushInputStream.java +33 -3
  53. data/ext/java/nokogiri/internals/ReaderNode.java +50 -8
  54. data/ext/java/nokogiri/internals/SaveContext.java +35 -2
  55. data/ext/java/nokogiri/internals/SchemaErrorHandler.java +34 -1
  56. data/ext/java/nokogiri/internals/XmlDeclHandler.java +32 -0
  57. data/ext/java/nokogiri/internals/XmlDomParser.java +32 -0
  58. data/ext/java/nokogiri/internals/XmlDomParserContext.java +43 -11
  59. data/ext/java/nokogiri/internals/XmlSaxParser.java +32 -0
  60. data/ext/java/nokogiri/internals/XsltExtensionFunction.java +72 -0
  61. data/ext/nokogiri/depend +358 -32
  62. data/ext/nokogiri/extconf.rb +1 -3
  63. data/ext/nokogiri/nokogiri.c +2 -0
  64. data/ext/nokogiri/nokogiri.h +7 -0
  65. data/ext/nokogiri/xml_dtd.c +2 -2
  66. data/ext/nokogiri/xml_io.c +2 -2
  67. data/ext/nokogiri/xml_node.c +31 -6
  68. data/ext/nokogiri/xml_node_set.c +1 -1
  69. data/ext/nokogiri/xml_sax_parser.c +1 -1
  70. data/ext/nokogiri/xml_sax_parser_context.c +40 -0
  71. data/ext/nokogiri/xml_xpath_context.c +33 -2
  72. data/ext/nokogiri/xslt_stylesheet.c +122 -6
  73. data/lib/nokogiri.rb +12 -5
  74. data/lib/nokogiri/css/generated_tokenizer.rb +1 -2
  75. data/lib/nokogiri/css/xpath_visitor.rb +15 -7
  76. data/lib/nokogiri/decorators/slop.rb +5 -3
  77. data/lib/nokogiri/html/document.rb +3 -3
  78. data/lib/nokogiri/html/document_fragment.rb +19 -17
  79. data/lib/nokogiri/version.rb +1 -1
  80. data/lib/nokogiri/xml/document.rb +26 -1
  81. data/lib/nokogiri/xml/document_fragment.rb +2 -2
  82. data/lib/nokogiri/xml/dtd.rb +11 -0
  83. data/lib/nokogiri/xml/node.rb +156 -45
  84. data/lib/nokogiri/xml/node_set.rb +2 -2
  85. data/lib/nokogiri/xml/reader.rb +36 -0
  86. data/lib/nokogiri/xml/sax/document.rb +4 -2
  87. data/lib/nokogiri/xslt.rb +9 -5
  88. data/lib/nokogiri/xslt/stylesheet.rb +1 -1
  89. data/tasks/cross_compile.rb +27 -8
  90. data/test/css/test_parser.rb +29 -18
  91. data/test/decorators/test_slop.rb +16 -0
  92. data/test/html/test_document_fragment.rb +46 -3
  93. data/test/html/test_node.rb +9 -0
  94. data/test/xml/sax/test_parser.rb +11 -3
  95. data/test/xml/sax/test_parser_context.rb +50 -0
  96. data/test/xml/sax/test_push_parser.rb +18 -1
  97. data/test/xml/test_document_fragment.rb +15 -8
  98. data/test/xml/test_dtd.rb +15 -0
  99. data/test/xml/test_node.rb +31 -2
  100. data/test/xml/test_node_reparenting.rb +59 -31
  101. data/test/xml/test_node_set.rb +13 -0
  102. data/test/xml/test_xpath.rb +32 -0
  103. data/test/xslt/test_custom_functions.rb +94 -0
  104. metadata +83 -81
  105. data/lib/nokogiri/nokogiri.jar +0 -0
  106. data/spec/helper.rb +0 -3
  107. data/spec/xml/reader_spec.rb +0 -307
@@ -38,7 +38,24 @@ module Nokogiri
38
38
  <p id="asdfasdf">
39
39
  eoxml
40
40
 
41
- assert_equal [["p", ["id", "asdfasdf"]]],
41
+ assert_equal [["p", [["id", "asdfasdf"]]]],
42
+ @parser.document.start_elements
43
+
44
+ @parser.<<(<<-eoxml)
45
+ <!-- This is a comment -->
46
+ Paragraph 1
47
+ </p>
48
+ eoxml
49
+ assert_equal [' This is a comment '], @parser.document.comments
50
+ @parser.finish
51
+ end
52
+
53
+ def test_start_element_with_namespaces
54
+ @parser.<<(<<-eoxml)
55
+ <p xmlns:foo="http://foo.example.com/">
56
+ eoxml
57
+
58
+ assert_equal [["p", [["xmlns:foo", "http://foo.example.com/"]]]],
42
59
  @parser.document.start_elements
43
60
 
44
61
  @parser.<<(<<-eoxml)
@@ -100,13 +100,13 @@ module Nokogiri
100
100
  def test_xml_fragment_with_leading_whitespace
101
101
  doc = " <div>b</div> "
102
102
  fragment = Nokogiri::XML::Document.new.fragment(doc)
103
- assert_equal "<div>b</div>", fragment.to_s
103
+ assert_equal " <div>b</div> ", fragment.to_s
104
104
  end
105
105
 
106
106
  def test_xml_fragment_with_leading_whitespace_and_newline
107
107
  doc = " \n<div>b</div> "
108
108
  fragment = Nokogiri::XML::Document.new.fragment(doc)
109
- assert_equal "<div>b</div>", fragment.to_s
109
+ assert_equal " \n<div>b</div> ", fragment.to_s
110
110
  end
111
111
 
112
112
  def test_fragment_children_search
@@ -147,12 +147,7 @@ module Nokogiri
147
147
 
148
148
  frag = doc.fragment "<bar:newnode></bar:newnode>"
149
149
  assert frag.children.first.namespace
150
- if Nokogiri.uses_libxml?
151
- assert_equal ns, frag.children.first.namespace
152
- else
153
- assert_equal ns.href, frag.children.first.namespace.href
154
- assert_equal ns.prefix, frag.children.first.namespace.prefix
155
- end
150
+ assert_equal ns, frag.children.first.namespace
156
151
  end
157
152
 
158
153
  def test_fragment_invalid_namespace_is_silently_ignored
@@ -180,6 +175,18 @@ module Nokogiri
180
175
  end
181
176
  assert fragment.children.respond_to?(:awesome!), fragment.children.class
182
177
  end
178
+
179
+ def test_for_libxml_in_context_fragment_parsing_bug_workaround
180
+ 10.times do
181
+ begin
182
+ fragment = Nokogiri::XML.fragment("<div></div>")
183
+ parent = fragment.children.first
184
+ child = parent.parse("<h1></h1>").first
185
+ parent.add_child child
186
+ end
187
+ GC.start
188
+ end
189
+ end
183
190
  end
184
191
  end
185
192
  end
@@ -29,11 +29,26 @@ module Nokogiri
29
29
  end
30
30
  end
31
31
 
32
+ def test_empty_attributes
33
+ dtd = Nokogiri::HTML("<html></html>").internal_subset
34
+ assert_equal Hash.new, dtd.attributes
35
+ end
36
+
32
37
  def test_attributes
33
38
  assert_equal ['width'], @dtd.attributes.keys
34
39
  assert_equal '0', @dtd.attributes['width'].default
35
40
  end
36
41
 
42
+ def test_keys
43
+ assert_equal ['width'], @dtd.keys
44
+ end
45
+
46
+ def test_each
47
+ hash = {}
48
+ @dtd.each { |key, value| hash[key] = value }
49
+ assert_equal @dtd.attributes, hash
50
+ end
51
+
37
52
  def test_namespace
38
53
  assert_raise NoMethodError do
39
54
  @dtd.namespace
@@ -82,18 +82,47 @@ module Nokogiri
82
82
  assert_equal 0, list.length
83
83
  end
84
84
 
85
+ def test_parse_config_option
86
+ node = @xml.root
87
+ options = nil
88
+ node.parse("<item></item>") do |config|
89
+ options = config
90
+ end
91
+ assert_equal Nokogiri::XML::ParseOptions::DEFAULT_XML, options.to_i
92
+ end
93
+
85
94
  # descriptive, not prescriptive.
86
95
  def test_parse_invalid_html_markup_results_in_empty_nodeset
87
96
  doc = Nokogiri::HTML("<html></html>")
88
97
  nodeset = doc.root.parse "<div><div>a</div><snippet>b</snippet></div>"
89
98
  assert_equal 1, doc.errors.length # "Tag snippet invalid"
99
+ assert_equal 1, nodeset.length
100
+ end
101
+
102
+ def test_node_context_parsing_of_malformed_html_fragment_with_recover_is_corrected
103
+ doc = HTML.parse "<html><body><div></div></body></html>"
104
+ context_node = doc.at_css "div"
105
+ nodeset = context_node.parse("<div </div>") do |options|
106
+ options.recover
107
+ end
108
+ assert_equal "<div></div>", nodeset.to_s
109
+ assert_equal 1, doc.errors.length
110
+ assert_equal 1, nodeset.length
111
+ end
112
+
113
+ def test_node_context_parsing_of_malformed_html_fragment_without_recover_is_not_corrected
114
+ doc = HTML.parse "<html><body><div></div></body></html>"
115
+ context_node = doc.at_css "div"
116
+ nodeset = context_node.parse("<div </div>") do |options|
117
+ options.strict
118
+ end
119
+ assert_equal 1, doc.errors.length
90
120
  assert_equal 0, nodeset.length
91
121
  end
92
122
 
93
123
  def test_parse_error_list
94
124
  error_count = @xml.errors.length
95
- list = @xml.root.parse('<hello>')
96
- assert_equal 0, list.length
125
+ @xml.root.parse('<hello>')
97
126
  assert(error_count < @xml.errors.length, "errors should have increased")
98
127
  end
99
128
 
@@ -50,21 +50,22 @@ module Nokogiri
50
50
  # end
51
51
 
52
52
  {
53
- :add_child => {:target => "/root/a1", :returns => :reparented, :children_tags => %w[text b1 b2]},
54
- :<< => {:target => "/root/a1", :returns => :reparented, :children_tags => %w[text b1 b2]},
53
+ :add_child => {:target => "/root/a1", :returns_self => false, :children_tags => %w[text b1 b2]},
54
+ :<< => {:target => "/root/a1", :returns_self => false, :children_tags => %w[text b1 b2]},
55
55
 
56
- :replace => {:target => "/root/a1/node()", :returns => :reparented, :children_tags => %w[b1 b2]},
57
- :swap => {:target => "/root/a1/node()", :returns => :self, :children_tags => %w[b1 b2]},
56
+ :replace => {:target => "/root/a1/node()", :returns_self => false, :children_tags => %w[b1 b2]},
57
+ :swap => {:target => "/root/a1/node()", :returns_self => true, :children_tags => %w[b1 b2]},
58
58
 
59
- :inner_html= => {:target => "/root/a1", :returns => :self, :children_tags => %w[b1 b2]},
59
+ :children= => {:target => "/root/a1", :returns_self => false, :children_tags => %w[b1 b2]},
60
+ :inner_html= => {:target => "/root/a1", :returns_self => true, :children_tags => %w[b1 b2]},
60
61
 
61
- :add_previous_sibling => {:target => "/root/a1/text()", :returns => :reparented, :children_tags => %w[b1 b2 text]},
62
- :previous= => {:target => "/root/a1/text()", :returns => :reparented, :children_tags => %w[b1 b2 text]},
63
- :before => {:target => "/root/a1/text()", :returns => :self, :children_tags => %w[b1 b2 text]},
62
+ :add_previous_sibling => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[b1 b2 text]},
63
+ :previous= => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[b1 b2 text]},
64
+ :before => {:target => "/root/a1/text()", :returns_self => true, :children_tags => %w[b1 b2 text]},
64
65
 
65
- :add_next_sibling => {:target => "/root/a1/text()", :returns => :reparented, :children_tags => %w[text b1 b2]},
66
- :next= => {:target => "/root/a1/text()", :returns => :reparented, :children_tags => %w[text b1 b2]},
67
- :after => {:target => "/root/a1/text()", :returns => :self, :children_tags => %w[text b1 b2]}
66
+ :add_next_sibling => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[text b1 b2]},
67
+ :next= => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[text b1 b2]},
68
+ :after => {:target => "/root/a1/text()", :returns_self => true, :children_tags => %w[text b1 b2]}
68
69
  }.each do |method, params|
69
70
 
70
71
  before do
@@ -95,11 +96,12 @@ module Nokogiri
95
96
  end
96
97
 
97
98
  it "returns the expected value" do
98
- if params[:returns] == :self
99
- sendee = @doc.at_xpath(params[:target])
100
- sendee.send(method, @other_node).must_equal sendee
99
+ sendee = @doc.at_xpath(params[:target])
100
+ result = sendee.send(method, @other_node)
101
+ if params[:returns_self]
102
+ result.must_equal sendee
101
103
  else
102
- @doc.at_xpath(params[:target]).send(method, @other_node).must_equal @other_node
104
+ result.must_equal @other_node
103
105
  end
104
106
  end
105
107
  end
@@ -110,6 +112,17 @@ module Nokogiri
110
112
  @doc.at_xpath(params[:target]).send(method, @fragment_string)
111
113
  @doc.xpath("/root/a1/node()").collect {|n| n.name}.must_equal params[:children_tags]
112
114
  end
115
+
116
+ it "returns the expected value" do
117
+ sendee = @doc.at_xpath(params[:target])
118
+ result = sendee.send(method, @fragment_string)
119
+ if params[:returns_self]
120
+ result.must_equal sendee
121
+ else
122
+ result.must_be_kind_of Nokogiri::XML::NodeSet
123
+ result.to_html.must_equal @fragment_string
124
+ end
125
+ end
113
126
  end
114
127
  describe "passed a fragment" do
115
128
  it "inserts the fragment roots in the proper position" do
@@ -153,18 +166,6 @@ module Nokogiri
153
166
  end
154
167
 
155
168
  describe "ad hoc node reparenting behavior" do
156
- before do
157
- @xml = Nokogiri::XML "<root><a1>First node</a1><a2>Second node</a2><a3>Third node</a3></root>"
158
- @html = Nokogiri::HTML(<<-eohtml)
159
- <html>
160
- <head></head>
161
- <body>
162
- <div class='baz'><a href="foo" class="bar">first</a></div>
163
- </body>
164
- </html>
165
- eohtml
166
- end
167
-
168
169
  describe "#add_child" do
169
170
  describe "given a new node with a namespace" do
170
171
  it "keeps the namespace" do
@@ -223,7 +224,34 @@ module Nokogiri
223
224
  end
224
225
  end
225
226
 
227
+ describe "#add_previous_sibling" do
228
+ it "should not merge text nodes during the operation" do
229
+ xml = Nokogiri::XML %Q(<root>text node</root>)
230
+ replacee = xml.root.children.first
231
+ replacee.add_previous_sibling "foo <p></p> bar"
232
+ assert_equal "foo <p></p> bartext node", xml.root.children.to_html
233
+ end
234
+ end
235
+
236
+ describe "#add_next_sibling" do
237
+ it "should not merge text nodes during the operation" do
238
+ xml = Nokogiri::XML %Q(<root>text node</root>)
239
+ replacee = xml.root.children.first
240
+ replacee.add_next_sibling "foo <p></p> bar"
241
+ assert_equal "text nodefoo <p></p> bar", xml.root.children.to_html
242
+ end
243
+ end
244
+
226
245
  describe "#replace" do
246
+ describe "a text node with a text node" do
247
+ it "should not merge text nodes during the operation" do
248
+ xml = Nokogiri::XML %Q(<root>text node</root>)
249
+ replacee = xml.root.children.first
250
+ replacee.replace "new text node"
251
+ assert_equal "new text node", xml.root.children.first.content
252
+ end
253
+ end
254
+
227
255
  describe "when a document has a default namespace" do
228
256
  before do
229
257
  @fruits = Nokogiri::XML(<<-eoxml)
@@ -260,10 +288,10 @@ module Nokogiri
260
288
  </root>
261
289
  EOHTML
262
290
 
263
- root = doc.at("root")
264
- a = root.at("a")
265
- b = a.at("b")
266
- c = a.at("c")
291
+ assert root = doc.at("root")
292
+ assert a = root.at("a")
293
+ assert b = a.at("b")
294
+ assert c = a.at("c")
267
295
  a.add_next_sibling(b.unlink)
268
296
  c.unlink
269
297
  end
@@ -431,6 +431,19 @@ module Nokogiri
431
431
  assert_equal 'employee', @xml.search("//wrapper").first.children[0].name
432
432
  end
433
433
 
434
+ def test_wrap_a_fragment
435
+ frag = Nokogiri::XML::DocumentFragment.parse <<-EOXML
436
+ <employees>
437
+ <employee>hello</employee>
438
+ <employee>goodbye</employee>
439
+ </employees>
440
+ EOXML
441
+ employees = frag.xpath ".//employee"
442
+ employees.wrap("<wrapper/>")
443
+ assert_equal 'wrapper', employees[0].parent.name
444
+ assert_equal 'employee', frag.at(".//wrapper").children.first.name
445
+ end
446
+
434
447
  def test_wrap_preserves_document_structure
435
448
  assert_equal "employeeId",
436
449
  @xml.at_xpath("//employee").children.detect{|j| ! j.text? }.name
@@ -61,6 +61,10 @@ module Nokogiri
61
61
  }.new
62
62
  end
63
63
 
64
+ def test_variable_binding
65
+ assert_equal 4, @xml.xpath('//address[@domestic=$value]', nil, :value => 'Yes').length
66
+ end
67
+
64
68
  def test_unknown_attribute
65
69
  assert_equal 0, @xml.xpath('//employee[@id="asdfasdf"]/@fooo').length
66
70
  assert_nil @xml.xpath('//employee[@id="asdfasdf"]/@fooo')[0]
@@ -200,6 +204,34 @@ module Nokogiri
200
204
  nokogiri = Nokogiri::HTML.parse(doc)
201
205
  assert nokogiri.xpath(xpath)
202
206
  end
207
+
208
+ def test_custom_xpath_handler_with_args_under_gc_pressure
209
+ # see http://github.com/tenderlove/nokogiri/issues/#issue/345
210
+ tool_inspector = Class.new do
211
+ def name_equals(nodeset, name, *args)
212
+ nodeset.all? do |node|
213
+ args.each { |thing| thing.inspect }
214
+ node["name"] == name
215
+ end
216
+ end
217
+ end.new
218
+
219
+ xml = <<-EOXML
220
+ <toolbox>
221
+ #{"<tool name='hammer'/><tool name='wrench'/>" * 10}
222
+ </toolbox>
223
+ EOXML
224
+ doc = Nokogiri::XML xml
225
+
226
+ # long list of long arguments, to apply GC pressure during
227
+ # ruby_funcall argument marshalling
228
+ xpath = ["//tool[name_equals(.,'hammer'"]
229
+ 1000.times { xpath << "'unused argument #{'x' * 1000}'" }
230
+ xpath << "'unused argument')]"
231
+ xpath = xpath.join(',')
232
+
233
+ assert_equal doc.xpath("//tool[@name='hammer']"), doc.xpath(xpath, tool_inspector)
234
+ end
203
235
  end
204
236
  end
205
237
  end
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "helper"
4
+
5
+ module Nokogiri
6
+ module XSLT
7
+ class TestCustomFunctions < Nokogiri::TestCase
8
+ def setup
9
+ super
10
+ @xml = Nokogiri.XML(<<-EOXML)
11
+ <?xml version="1.0" encoding="UTF-8"?>
12
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
13
+ "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">
14
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
15
+ <head>
16
+ <meta http-equiv="Content-type" content="application/xhtml+xml"/>
17
+ <title>Foo</title>
18
+ </head>
19
+ <body>
20
+ <h1>Foo</h1>
21
+ <p>Lorem ipsum.</p>
22
+ </body>
23
+ </html>
24
+ EOXML
25
+ end
26
+
27
+ def test_function
28
+ skip("Pure Java version doesn't support this feature.") if !Nokogiri.uses_libxml?
29
+ foo = Class.new do
30
+ def capitalize nodes
31
+ nodes.first.content.upcase
32
+ end
33
+ end
34
+
35
+ XSLT.register "http://e.org/functions", foo
36
+
37
+ xsl = Nokogiri.XSLT(<<-EOXSL)
38
+ <?xml version="1.0"?>
39
+ <xsl:stylesheet version="1.0"
40
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
41
+ xmlns:f="http://e.org/functions"
42
+ extension-element-prefixes="f">
43
+
44
+ <xsl:template match="text()">
45
+ <xsl:copy-of select="f:capitalize(.)"/>
46
+ </xsl:template>
47
+
48
+ <xsl:template match="@*|node()">
49
+ <xsl:copy>
50
+ <xsl:apply-templates select="@*|node()"/>
51
+ <xsl:apply-imports/>
52
+ </xsl:copy>
53
+ </xsl:template>
54
+
55
+ </xsl:stylesheet>
56
+ EOXSL
57
+ result = xsl.transform @xml
58
+ assert_equal 'FOO', result.css('title').first.text
59
+ end
60
+
61
+ def test_function_XSLT
62
+ skip("Pure Java version doesn't support this feature.") if !Nokogiri.uses_libxml?
63
+ foo = Class.new do
64
+ def america nodes
65
+ nodes.first.content.upcase
66
+ end
67
+ end
68
+
69
+ xsl = Nokogiri.XSLT(<<-EOXSL, "http://e.org/functions" => foo)
70
+ <?xml version="1.0"?>
71
+ <xsl:stylesheet version="1.0"
72
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
73
+ xmlns:f="http://e.org/functions"
74
+ extension-element-prefixes="f">
75
+
76
+ <xsl:template match="text()">
77
+ <xsl:copy-of select="f:america(.)"/>
78
+ </xsl:template>
79
+
80
+ <xsl:template match="@*|node()">
81
+ <xsl:copy>
82
+ <xsl:apply-templates select="@*|node()"/>
83
+ <xsl:apply-imports/>
84
+ </xsl:copy>
85
+ </xsl:template>
86
+
87
+ </xsl:stylesheet>
88
+ EOXSL
89
+ result = xsl.transform @xml
90
+ assert_equal 'FOO', result.css('title').first.text
91
+ end
92
+ end
93
+ end
94
+ end