nokogiri-maglev- 1.5.0.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGELOG.ja.rdoc +56 -12
  2. data/CHANGELOG.rdoc +49 -0
  3. data/C_CODING_STYLE.rdoc +27 -0
  4. data/Manifest.txt +4 -0
  5. data/README.rdoc +11 -7
  6. data/Rakefile +42 -27
  7. data/bin/nokogiri +10 -2
  8. data/ext/nokogiri/extconf.rb +11 -3
  9. data/ext/nokogiri/html_document.c +16 -0
  10. data/ext/nokogiri/html_sax_parser_context.c +59 -37
  11. data/ext/nokogiri/html_sax_push_parser.c +87 -0
  12. data/ext/nokogiri/html_sax_push_parser.h +9 -0
  13. data/ext/nokogiri/nokogiri.c +7 -9
  14. data/ext/nokogiri/nokogiri.h +3 -0
  15. data/ext/nokogiri/xml_document.c +101 -3
  16. data/ext/nokogiri/xml_document.h +3 -3
  17. data/ext/nokogiri/xml_node.c +151 -58
  18. data/ext/nokogiri/xml_node_set.c +169 -120
  19. data/ext/nokogiri/xml_node_set.h +5 -0
  20. data/ext/nokogiri/xml_sax_parser_context.c +64 -41
  21. data/ext/nokogiri/xml_text.c +2 -0
  22. data/ext/nokogiri/xml_xpath_context.c +31 -25
  23. data/ext/nokogiri/xslt_stylesheet.c +62 -16
  24. data/ext/nokogiri/xslt_stylesheet.h +5 -0
  25. data/lib/nokogiri/css/parser.rb +165 -159
  26. data/lib/nokogiri/css/parser.y +6 -3
  27. data/lib/nokogiri/css/tokenizer.rb +1 -1
  28. data/lib/nokogiri/css/tokenizer.rex +1 -1
  29. data/lib/nokogiri/html.rb +1 -0
  30. data/lib/nokogiri/html/document.rb +82 -42
  31. data/lib/nokogiri/html/sax/push_parser.rb +16 -0
  32. data/lib/nokogiri/version.rb +1 -1
  33. data/lib/nokogiri/xml.rb +6 -0
  34. data/lib/nokogiri/xml/builder.rb +7 -1
  35. data/lib/nokogiri/xml/document.rb +32 -17
  36. data/lib/nokogiri/xml/document_fragment.rb +6 -1
  37. data/lib/nokogiri/xml/node.rb +40 -9
  38. data/lib/nokogiri/xslt.rb +5 -1
  39. data/tasks/cross_compile.rb +1 -0
  40. data/tasks/nokogiri.org.rb +6 -0
  41. data/tasks/test.rb +1 -0
  42. data/test/css/test_xpath_visitor.rb +6 -0
  43. data/test/helper.rb +1 -0
  44. data/test/html/test_document.rb +26 -0
  45. data/test/html/test_document_fragment.rb +1 -2
  46. data/test/test_memory_leak.rb +81 -1
  47. data/test/test_xslt_transforms.rb +152 -123
  48. data/test/xml/test_builder.rb +24 -2
  49. data/test/xml/test_c14n.rb +151 -0
  50. data/test/xml/test_document.rb +48 -0
  51. data/test/xml/test_namespace.rb +5 -0
  52. data/test/xml/test_node.rb +82 -1
  53. data/test/xml/test_node_attributes.rb +19 -0
  54. data/test/xml/test_node_inheritance.rb +32 -0
  55. data/test/xml/test_node_reparenting.rb +32 -0
  56. data/test/xml/test_node_set.rb +16 -8
  57. data/test/xml/test_reader_encoding.rb +16 -0
  58. data/test/xml/test_unparented_node.rb +32 -0
  59. data/test/xml/test_xinclude.rb +83 -0
  60. data/test/xml/test_xpath.rb +22 -0
  61. metadata +208 -241
@@ -69,6 +69,10 @@ rule
69
69
  : '.' IDENT { result = Node.new(:CLASS_CONDITION, [val[1]]) }
70
70
  ;
71
71
  element_name
72
+ : namespaced_ident
73
+ | '*' { result = Node.new(:ELEMENT_NAME, val) }
74
+ ;
75
+ namespaced_ident
72
76
  : namespace '|' IDENT {
73
77
  result = Node.new(:ELEMENT_NAME,
74
78
  [[val.first, val.last].compact.join(':')]
@@ -78,16 +82,15 @@ rule
78
82
  name = @namespaces.key?('xmlns') ? "xmlns:#{val.first}" : val.first
79
83
  result = Node.new(:ELEMENT_NAME, [name])
80
84
  }
81
- | '*' { result = Node.new(:ELEMENT_NAME, val) }
82
85
  ;
83
86
  namespace
84
87
  : IDENT { result = val[0] }
85
88
  |
86
89
  ;
87
90
  attrib
88
- : LSQUARE IDENT attrib_val_0or1 RSQUARE {
91
+ : LSQUARE namespaced_ident attrib_val_0or1 RSQUARE {
89
92
  result = Node.new(:ATTRIBUTE_CONDITION,
90
- [Node.new(:ELEMENT_NAME, [val[1]])] + (val[2] || [])
93
+ [val[1]] + (val[2] || [])
91
94
  )
92
95
  }
93
96
  | LSQUARE function attrib_val_0or1 RSQUARE {
@@ -6,7 +6,7 @@
6
6
 
7
7
  module Nokogiri
8
8
  module CSS
9
- class Tokenizer
9
+ class Tokenizer # :nodoc:
10
10
  require 'strscan'
11
11
 
12
12
  class ScanError < StandardError ; end
@@ -1,6 +1,6 @@
1
1
  module Nokogiri
2
2
  module CSS
3
- class Tokenizer
3
+ class Tokenizer # :nodoc:
4
4
 
5
5
  macro
6
6
  nl \n|\r\n|\r|\f
data/lib/nokogiri/html.rb CHANGED
@@ -3,6 +3,7 @@ require 'nokogiri/html/document'
3
3
  require 'nokogiri/html/document_fragment'
4
4
  require 'nokogiri/html/sax/parser_context'
5
5
  require 'nokogiri/html/sax/parser'
6
+ require 'nokogiri/html/sax/push_parser'
6
7
  require 'nokogiri/html/element_description'
7
8
  require 'nokogiri/html/element_description_defaults'
8
9
 
@@ -19,7 +19,9 @@ module Nokogiri
19
19
 
20
20
  def meta_content_type
21
21
  css('meta[@http-equiv]').find { |node|
22
- node['http-equiv'] =~ /\AContent-Type\z/i
22
+ node['http-equiv'] =~ /\AContent-Type\z/i and
23
+ !node['content'].nil? and
24
+ !node['content'].empty?
23
25
  }
24
26
  end
25
27
  private :meta_content_type
@@ -92,17 +94,22 @@ module Nokogiri
92
94
  if string_or_io.respond_to?(:read)
93
95
  url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
94
96
  if !encoding
95
- # Perform advanced encoding detection that libxml2 does
96
- # not do.
97
+ # Libxml2's parser has poor support for encoding
98
+ # detection. First, it does not recognize the HTML5
99
+ # style meta charset declaration. Secondly, even if it
100
+ # successfully detects an encoding hint, it does not
101
+ # re-decode or re-parse the preceding part which may be
102
+ # garbled.
103
+ #
104
+ # EncodingReader aims to perform advanced encoding
105
+ # detection beyond what Libxml2 does, and to emulate
106
+ # rewinding of a stream and make Libxml2 redo parsing
107
+ # from the start when an encoding hint is found.
97
108
  string_or_io = EncodingReader.new(string_or_io)
98
109
  begin
99
110
  return read_io(string_or_io, url, encoding, options.to_i)
100
- rescue EncodingFoundException => e
101
- # A retry is required because libxml2 has a problem in
102
- # that it cannot switch encoding well in the middle of
103
- # parsing, especially if it has already seen a
104
- # non-ASCII character when it finds an encoding hint.
105
- encoding = e.encoding
111
+ rescue EncodingFound => e
112
+ encoding = e.found_encoding
106
113
  end
107
114
  end
108
115
  return read_io(string_or_io, url, encoding, options.to_i)
@@ -111,19 +118,17 @@ module Nokogiri
111
118
  # read_memory pukes on empty docs
112
119
  return new if string_or_io.nil? or string_or_io.empty?
113
120
 
114
- if !encoding
115
- encoding = EncodingReader.detect_encoding(string_or_io)
116
- end
121
+ encoding ||= EncodingReader.detect_encoding(string_or_io)
117
122
 
118
123
  read_memory(string_or_io, url, encoding, options.to_i)
119
124
  end
120
125
  end
121
126
 
122
- class EncodingFoundException < Exception # :nodoc:
123
- attr_reader :encoding
127
+ class EncodingFound < StandardError # :nodoc:
128
+ attr_reader :found_encoding
124
129
 
125
130
  def initialize(encoding)
126
- @encoding = encoding
131
+ @found_encoding = encoding
127
132
  super("encoding found: %s" % encoding)
128
133
  end
129
134
  end
@@ -131,57 +136,91 @@ module Nokogiri
131
136
  class EncodingReader # :nodoc:
132
137
  class SAXHandler < Nokogiri::XML::SAX::Document # :nodoc:
133
138
  attr_reader :encoding
134
-
135
- def found(encoding)
136
- @encoding = encoding
137
- throw :found
139
+
140
+ def initialize
141
+ @encoding = nil
142
+ super()
138
143
  end
139
-
140
- def not_found(encoding)
141
- found nil
144
+
145
+ def start_element(name, attrs = [])
146
+ return unless name == 'meta'
147
+ attr = Hash[attrs]
148
+ charset = attr['charset'] and
149
+ @encoding = charset
150
+ http_equiv = attr['http-equiv'] and
151
+ http_equiv.match(/\AContent-Type\z/i) and
152
+ content = attr['content'] and
153
+ m = content.match(/;\s*charset\s*=\s*([\w-]+)/) and
154
+ @encoding = m[1]
155
+ end
156
+ end
157
+
158
+ class JumpSAXHandler < SAXHandler
159
+ def initialize(jumptag)
160
+ @jumptag = jumptag
161
+ super()
142
162
  end
143
163
 
144
164
  def start_element(name, attrs = [])
145
- case name
146
- when /\A(?:div|h1|img|p|br)\z/
147
- not_found
148
- when 'meta'
149
- attr = Hash[attrs]
150
- charset = attr['charset'] and
151
- found charset
152
- http_equiv = attr['http-equiv'] and
153
- http_equiv.match(/\AContent-Type\z/i) and
154
- content = attr['content'] and
155
- m = content.match(/;\s*charset\s*=\s*([\w-]+)/) and
156
- found m[1]
157
- end
165
+ super
166
+ throw @jumptag, @encoding if @encoding
167
+ throw @jumptag, nil if name =~ /\A(?:div|h1|img|p|br)\z/
158
168
  end
159
169
  end
160
170
 
161
171
  def self.detect_encoding(chunk)
172
+ if Nokogiri.jruby? && EncodingReader.is_jruby_without_fix?
173
+ return EncodingReader.detect_encoding_for_jruby_without_fix(chunk)
174
+ end
162
175
  m = chunk.match(/\A(<\?xml[ \t\r\n]+[^>]*>)/) and
163
176
  return Nokogiri.XML(m[1]).encoding
164
177
 
165
178
  if Nokogiri.jruby?
166
179
  m = chunk.match(/(<meta\s)(.*)(charset\s*=\s*([\w-]+))(.*)/i) and
167
180
  return m[4]
181
+ catch(:encoding_found) {
182
+ Nokogiri::HTML::SAX::Parser.new(JumpSAXHandler.new(:encoding_found.to_s)).parse(chunk)
183
+ nil
184
+ }
185
+ else
186
+ handler = SAXHandler.new
187
+ parser = Nokogiri::HTML::SAX::PushParser.new(handler)
188
+ parser << chunk rescue Nokogiri::SyntaxError
189
+ handler.encoding
168
190
  end
191
+ end
192
+
193
+ def self.is_jruby_without_fix?
194
+ JRUBY_VERSION.split('.').join.to_i < 165
195
+ end
169
196
 
170
- handler = SAXHandler.new
171
- parser = Nokogiri::HTML::SAX::Parser.new(handler)
172
- catch(:found) {
173
- parser.parse(chunk)
197
+ def self.detect_encoding_for_jruby_without_fix(chunk)
198
+ m = chunk.match(/\A(<\?xml[ \t\r\n]+[^>]*>)/) and
199
+ return Nokogiri.XML(m[1]).encoding
200
+
201
+ m = chunk.match(/(<meta\s)(.*)(charset\s*=\s*([\w-]+))(.*)/i) and
202
+ return m[4]
203
+
204
+ catch(:encoding_found) {
205
+ Nokogiri::HTML::SAX::Parser.new(JumpSAXHandler.new(:encoding_found.to_s)).parse(chunk)
206
+ nil
174
207
  }
175
- handler.encoding
176
- rescue
208
+ rescue Nokogiri::SyntaxError, RuntimeError
209
+ # Ignore parser errors that nokogiri may raise
177
210
  nil
178
211
  end
179
212
 
180
213
  def initialize(io)
181
214
  @io = io
182
215
  @firstchunk = nil
216
+ @encoding_found = nil
183
217
  end
184
218
 
219
+ # This method is used by the C extension so that
220
+ # Nokogiri::HTML::Document#read_io() does not leak memory when
221
+ # EncodingFound is raised.
222
+ attr_reader :encoding_found
223
+
185
224
  def read(len)
186
225
  # no support for a call without len
187
226
 
@@ -193,9 +232,10 @@ module Nokogiri
193
232
  # achieve advanced encoding detection.
194
233
  if encoding = EncodingReader.detect_encoding(@firstchunk)
195
234
  # The first chunk is stored for the next read in retry.
196
- raise EncodingFoundException, encoding
235
+ raise @encoding_found = EncodingFound.new(encoding)
197
236
  end
198
237
  end
238
+ @encoding_found = nil
199
239
 
200
240
  ret = @firstchunk.slice!(0, len)
201
241
  if (len -= ret.length) > 0
@@ -0,0 +1,16 @@
1
+ module Nokogiri
2
+ module HTML
3
+ module SAX
4
+ class PushParser
5
+ def initialize(doc = XML::SAX::Document.new, file_name = nil, encoding = 'UTF-8')
6
+ @document = doc
7
+ @encoding = encoding
8
+ @sax_parser = HTML::SAX::Parser.new(doc, @encoding)
9
+
10
+ ## Create our push parser context
11
+ initialize_native(@sax_parser, file_name, @encoding)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,6 @@
1
1
  module Nokogiri
2
2
  # The version of Nokogiri you are using
3
- VERSION = '1.5.0.1'
3
+ VERSION = '1.5.2'
4
4
 
5
5
  class VersionInfo # :nodoc:
6
6
  def jruby?
data/lib/nokogiri/xml.rb CHANGED
@@ -35,6 +35,12 @@ module Nokogiri
35
35
  end
36
36
 
37
37
  module XML
38
+ # Original C14N 1.0 spec canonicalization
39
+ XML_C14N_1_0 = 0
40
+ # Exclusive C14N 1.0 spec canonicalization
41
+ XML_C14N_EXCLUSIVE_1_0 = 1
42
+ # C14N 1.1 spec canonicalization
43
+ XML_C14N_1_1 = 2
38
44
  class << self
39
45
  ###
40
46
  # Parse an XML document using the Nokogiri::XML::Reader API. See
@@ -306,7 +306,13 @@ module Nokogiri
306
306
  ###
307
307
  # Create a CDATA Node with content of +string+
308
308
  def cdata string
309
- insert(doc.create_cdata(string))
309
+ insert doc.create_cdata(string)
310
+ end
311
+
312
+ ###
313
+ # Create a Comment Node with content of +string+
314
+ def comment string
315
+ insert doc.create_comment(string)
310
316
  end
311
317
 
312
318
  ###
@@ -8,6 +8,12 @@ module Nokogiri
8
8
  # For searching a Document, see Nokogiri::XML::Node#css and
9
9
  # Nokogiri::XML::Node#xpath
10
10
  class Document < Nokogiri::XML::Node
11
+ # I'm ignoring unicode characters here.
12
+ # See http://www.w3.org/TR/REC-xml-names/#ns-decl for more details.
13
+ NCNAME_START_CHAR = "A-Za-z_"
14
+ NCNAME_CHAR = NCNAME_START_CHAR + "\\-.0-9"
15
+ NCNAME_RE = /^xmlns(:[#{NCNAME_START_CHAR}][#{NCNAME_CHAR}]*)?$/
16
+
11
17
  ##
12
18
  # Parse an XML file. +string_or_io+ may be a String, or any object that
13
19
  # responds to _read_ and _close_ such as an IO, or StringIO.
@@ -17,20 +23,23 @@ module Nokogiri
17
23
  # Nokogiri::XML::ParseOptions::RECOVER. See the constants in
18
24
  # Nokogiri::XML::ParseOptions.
19
25
  def self.parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML, &block
20
-
21
26
  options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
22
27
  # Give the options to the user
23
28
  yield options if block_given?
24
29
 
25
- if string_or_io.respond_to?(:read)
30
+ doc = if string_or_io.respond_to?(:read)
26
31
  url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
27
- return read_io(string_or_io, url, encoding, options.to_i)
32
+ read_io(string_or_io, url, encoding, options.to_i)
33
+ else
34
+ # read_memory pukes on empty docs
35
+ return new if string_or_io.nil? or string_or_io.empty?
36
+ read_memory(string_or_io, url, encoding, options.to_i)
28
37
  end
29
38
 
30
- # read_memory pukes on empty docs
31
- return new if string_or_io.nil? or string_or_io.empty?
39
+ # do xinclude processing
40
+ doc.do_xinclude(options) if options.xinclude?
32
41
 
33
- read_memory(string_or_io, url, encoding, options.to_i)
42
+ return doc
34
43
  end
35
44
 
36
45
  # A list of Nokogiri::XML::SyntaxError found when parsing a document
@@ -57,7 +66,7 @@ module Nokogiri
57
66
  when Hash
58
67
  arg.each { |k,v|
59
68
  key = k.to_s
60
- if key =~ /^xmlns(:\w+)?$/
69
+ if key =~ NCNAME_RE
61
70
  ns_name = key.split(":", 2)[1]
62
71
  elm.add_namespace_definition ns_name, v
63
72
  next
@@ -71,14 +80,19 @@ module Nokogiri
71
80
  elm
72
81
  end
73
82
 
74
- # Create a text node with +text+
75
- def create_text_node text, &block
76
- Nokogiri::XML::Text.new(text.to_s, self, &block)
83
+ # Create a Text Node with +string+
84
+ def create_text_node string, &block
85
+ Nokogiri::XML::Text.new string.to_s, self, &block
86
+ end
87
+
88
+ # Create a CDATA Node containing +string+
89
+ def create_cdata string, &block
90
+ Nokogiri::XML::CDATA.new self, string.to_s, &block
77
91
  end
78
92
 
79
- # Create a CDATA element containing +text+
80
- def create_cdata text
81
- Nokogiri::XML::CDATA.new(self, text.to_s)
93
+ # Create a Comment Node containing +string+
94
+ def create_comment string, &block
95
+ Nokogiri::XML::Comment.new self, string.to_s, &block
82
96
  end
83
97
 
84
98
  # The name of this document. Always returns "document"
@@ -194,11 +208,12 @@ module Nokogiri
194
208
  undef_method :add_namespace_definition, :attributes
195
209
  undef_method :namespace_definitions, :line, :add_namespace
196
210
 
197
- def add_child child
211
+ def add_child node_or_tags
198
212
  raise "Document already has a root node" if root
199
- if child.type == Node::DOCUMENT_FRAG_NODE
200
- raise "Document cannot have multiple root nodes" if child.children.size > 1
201
- super(child.children.first)
213
+ node_or_tags = coerce(node_or_tags)
214
+ if node_or_tags.is_a?(XML::NodeSet)
215
+ raise "Document cannot have multiple root nodes" if node_or_tags.size > 1
216
+ super(node_or_tags.first)
202
217
  else
203
218
  super
204
219
  end
@@ -11,7 +11,12 @@ module Nokogiri
11
11
  return self unless tags
12
12
 
13
13
  children = if ctx
14
- ctx.parse(tags)
14
+ # Fix for issue#490
15
+ if Nokogiri.jruby?
16
+ ctx.parse("<root>#{tags}</root>").xpath("/root/node()")
17
+ else
18
+ ctx.parse(tags)
19
+ end
15
20
  else
16
21
  XML::Document.parse("<root>#{tags}</root>") \
17
22
  .xpath("/root/node()")
@@ -255,6 +255,12 @@ module Nokogiri
255
255
  get(name.to_s)
256
256
  end
257
257
 
258
+ ###
259
+ # Set the attribute value for the attribute +name+ to +value+
260
+ def []= name, value
261
+ set name.to_s, value
262
+ end
263
+
258
264
  ###
259
265
  # Add +node_or_tags+ as a child of this Node.
260
266
  # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
@@ -291,6 +297,8 @@ module Nokogiri
291
297
  #
292
298
  # Also see related method +before+.
293
299
  def add_previous_sibling node_or_tags
300
+ raise ArgumentError.new("A document may not have multiple root nodes.") if parent.is_a?(XML::Document) && !node_or_tags.is_a?(XML::ProcessingInstruction)
301
+
294
302
  node_or_tags = coerce(node_or_tags)
295
303
  if node_or_tags.is_a?(XML::NodeSet)
296
304
  if text?
@@ -315,6 +323,8 @@ module Nokogiri
315
323
  #
316
324
  # Also see related method +after+.
317
325
  def add_next_sibling node_or_tags
326
+ raise ArgumentError.new("A document may not have multiple root nodes.") if parent.is_a?(XML::Document)
327
+
318
328
  node_or_tags = coerce(node_or_tags)
319
329
  if node_or_tags.is_a?(XML::NodeSet)
320
330
  if text?
@@ -452,9 +462,9 @@ module Nokogiri
452
462
  # If you need to distinguish attributes with the same name, with different namespaces
453
463
  # use #attribute_nodes instead.
454
464
  def attributes
455
- Hash[*(attribute_nodes.map { |node|
465
+ Hash[attribute_nodes.map { |node|
456
466
  [node.node_name, node]
457
- }.flatten)]
467
+ }]
458
468
  end
459
469
 
460
470
  ###
@@ -471,9 +481,9 @@ module Nokogiri
471
481
 
472
482
  ###
473
483
  # Iterate over each attribute name and value pair for this Node.
474
- def each &block
484
+ def each
475
485
  attribute_nodes.each { |node|
476
- block.call([node.node_name, node.value])
486
+ yield [node.node_name, node.value]
477
487
  }
478
488
  end
479
489
 
@@ -555,7 +565,7 @@ module Nokogiri
555
565
  # default namespaces set on ancestor will NOT be, even if self
556
566
  # has no explicit default namespace.
557
567
  def namespaces
558
- Hash[*namespace_scopes.map { |nd|
568
+ Hash[namespace_scopes.map { |nd|
559
569
  key = ['xmlns', nd.prefix].compact.join(':')
560
570
  if RUBY_VERSION >= '1.9' && document.encoding
561
571
  begin
@@ -564,7 +574,7 @@ module Nokogiri
564
574
  end
565
575
  end
566
576
  [key, nd.href]
567
- }.flatten]
577
+ }]
568
578
  end
569
579
 
570
580
  # Returns true if this is a Comment
@@ -766,8 +776,7 @@ module Nokogiri
766
776
  #
767
777
  # See Node#write_to for a list of +options+
768
778
  def to_xml options = {}
769
- options[:save_with] |= SaveOptions::DEFAULT_XML if options[:save_with]
770
- options[:save_with] = SaveOptions::DEFAULT_XML unless options[:save_with]
779
+ options[:save_with] ||= SaveOptions::DEFAULT_XML
771
780
  serialize(options)
772
781
  end
773
782
 
@@ -865,6 +874,28 @@ module Nokogiri
865
874
  compare other
866
875
  end
867
876
 
877
+ ###
878
+ # Do xinclude substitution on the subtree below node. If given a block, a
879
+ # Nokogiri::XML::ParseOptions object initialized from +options+, will be
880
+ # passed to it, allowing more convenient modification of the parser options.
881
+ def do_xinclude options = XML::ParseOptions::DEFAULT_XML, &block
882
+ options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
883
+
884
+ # give options to user
885
+ yield options if block_given?
886
+
887
+ # call c extension
888
+ process_xincludes(options.to_i)
889
+ end
890
+
891
+ def canonicalize(mode=XML::XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false)
892
+ c14n_root = self
893
+ document.canonicalize(mode, inclusive_namespaces, with_comments) do |node, parent|
894
+ tn = node.is_a?(XML::Node) ? node : parent
895
+ tn == c14n_root || tn.ancestors.include?(c14n_root)
896
+ end
897
+ end
898
+
868
899
  private
869
900
 
870
901
  def extract_params params # :nodoc:
@@ -893,7 +924,7 @@ module Nokogiri
893
924
  return data.children if data.is_a?(XML::DocumentFragment)
894
925
  return fragment(data).children if data.is_a?(String)
895
926
 
896
- if data.is_a?(Document) || !data.is_a?(XML::Node)
927
+ if data.is_a?(Document) || data.is_a?(XML::Attr) || !data.is_a?(XML::Node)
897
928
  raise ArgumentError, <<-EOERR
898
929
  Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
899
930
  (You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)