nokogiri 1.3.3 → 1.4.0

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 (201) hide show
  1. data/CHANGELOG.ja.rdoc +48 -3
  2. data/CHANGELOG.rdoc +42 -0
  3. data/Manifest.txt +44 -29
  4. data/README.ja.rdoc +0 -2
  5. data/README.rdoc +4 -7
  6. data/Rakefile +42 -6
  7. data/bin/nokogiri +7 -5
  8. data/ext/nokogiri/extconf.rb +5 -21
  9. data/ext/nokogiri/html_document.c +14 -50
  10. data/ext/nokogiri/html_element_description.c +7 -7
  11. data/ext/nokogiri/html_entity_lookup.c +6 -4
  12. data/ext/nokogiri/html_sax_parser_context.c +92 -0
  13. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  14. data/ext/nokogiri/nokogiri.c +9 -3
  15. data/ext/nokogiri/nokogiri.h +16 -20
  16. data/ext/nokogiri/xml_attr.c +1 -1
  17. data/ext/nokogiri/xml_attribute_decl.c +67 -0
  18. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  19. data/ext/nokogiri/xml_cdata.c +6 -5
  20. data/ext/nokogiri/xml_comment.c +3 -2
  21. data/ext/nokogiri/xml_document.c +93 -23
  22. data/ext/nokogiri/xml_document_fragment.c +1 -3
  23. data/ext/nokogiri/xml_dtd.c +63 -6
  24. data/ext/nokogiri/xml_element_content.c +123 -0
  25. data/ext/nokogiri/xml_element_content.h +10 -0
  26. data/ext/nokogiri/xml_element_decl.c +69 -0
  27. data/ext/nokogiri/xml_element_decl.h +9 -0
  28. data/ext/nokogiri/xml_entity_decl.c +97 -0
  29. data/ext/nokogiri/xml_entity_decl.h +10 -0
  30. data/ext/nokogiri/xml_entity_reference.c +1 -1
  31. data/ext/nokogiri/xml_io.c +10 -3
  32. data/ext/nokogiri/xml_io.h +1 -0
  33. data/ext/nokogiri/xml_namespace.c +2 -2
  34. data/ext/nokogiri/xml_node.c +139 -34
  35. data/ext/nokogiri/xml_node.h +0 -1
  36. data/ext/nokogiri/xml_node_set.c +23 -16
  37. data/ext/nokogiri/xml_processing_instruction.c +1 -1
  38. data/ext/nokogiri/xml_reader.c +78 -50
  39. data/ext/nokogiri/xml_sax_parser.c +109 -168
  40. data/ext/nokogiri/xml_sax_parser.h +33 -0
  41. data/ext/nokogiri/xml_sax_parser_context.c +155 -0
  42. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  43. data/ext/nokogiri/xml_sax_push_parser.c +11 -6
  44. data/ext/nokogiri/xml_syntax_error.c +63 -12
  45. data/ext/nokogiri/xml_text.c +4 -3
  46. data/ext/nokogiri/xml_xpath.c +1 -1
  47. data/ext/nokogiri/xml_xpath_context.c +12 -25
  48. data/ext/nokogiri/xslt_stylesheet.c +3 -3
  49. data/lib/nokogiri.rb +4 -4
  50. data/lib/nokogiri/css/generated_tokenizer.rb +1 -0
  51. data/lib/nokogiri/css/node.rb +1 -9
  52. data/lib/nokogiri/css/xpath_visitor.rb +11 -21
  53. data/lib/nokogiri/ffi/html/document.rb +0 -9
  54. data/lib/nokogiri/ffi/html/sax/parser_context.rb +38 -0
  55. data/lib/nokogiri/ffi/io_callbacks.rb +4 -2
  56. data/lib/nokogiri/ffi/libxml.rb +44 -10
  57. data/lib/nokogiri/ffi/structs/common_node.rb +1 -1
  58. data/lib/nokogiri/ffi/structs/xml_attribute.rb +27 -0
  59. data/lib/nokogiri/ffi/structs/xml_dtd.rb +3 -1
  60. data/lib/nokogiri/ffi/structs/xml_element.rb +26 -0
  61. data/lib/nokogiri/ffi/structs/xml_element_content.rb +17 -0
  62. data/lib/nokogiri/ffi/structs/xml_entity.rb +32 -0
  63. data/lib/nokogiri/ffi/structs/xml_enumeration.rb +12 -0
  64. data/lib/nokogiri/ffi/structs/xml_parser_context.rb +19 -0
  65. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +4 -3
  66. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +1 -1
  67. data/lib/nokogiri/ffi/xml/attribute_decl.rb +27 -0
  68. data/lib/nokogiri/ffi/xml/comment.rb +2 -2
  69. data/lib/nokogiri/ffi/xml/document.rb +29 -12
  70. data/lib/nokogiri/ffi/xml/document_fragment.rb +0 -5
  71. data/lib/nokogiri/ffi/xml/dtd.rb +14 -3
  72. data/lib/nokogiri/ffi/xml/element_content.rb +43 -0
  73. data/lib/nokogiri/ffi/xml/element_decl.rb +19 -0
  74. data/lib/nokogiri/ffi/xml/entity_decl.rb +27 -0
  75. data/lib/nokogiri/ffi/xml/node.rb +45 -5
  76. data/lib/nokogiri/ffi/xml/node_set.rb +1 -1
  77. data/lib/nokogiri/ffi/xml/reader.rb +45 -24
  78. data/lib/nokogiri/ffi/xml/sax/parser.rb +27 -34
  79. data/lib/nokogiri/ffi/xml/sax/parser_context.rb +67 -0
  80. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +5 -4
  81. data/lib/nokogiri/ffi/xml/syntax_error.rb +31 -16
  82. data/lib/nokogiri/ffi/xml/text.rb +2 -2
  83. data/lib/nokogiri/html.rb +1 -0
  84. data/lib/nokogiri/html/document.rb +39 -24
  85. data/lib/nokogiri/html/sax/parser.rb +2 -2
  86. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  87. data/lib/nokogiri/version.rb +1 -1
  88. data/lib/nokogiri/xml.rb +6 -1
  89. data/lib/nokogiri/xml/attr.rb +5 -0
  90. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  91. data/lib/nokogiri/xml/builder.rb +121 -13
  92. data/lib/nokogiri/xml/character_data.rb +7 -0
  93. data/lib/nokogiri/xml/document.rb +43 -29
  94. data/lib/nokogiri/xml/document_fragment.rb +26 -6
  95. data/lib/nokogiri/xml/dtd.rb +5 -5
  96. data/lib/nokogiri/xml/element_content.rb +36 -0
  97. data/lib/nokogiri/xml/element_decl.rb +13 -0
  98. data/lib/nokogiri/xml/entity_decl.rb +15 -0
  99. data/lib/nokogiri/xml/fragment_handler.rb +22 -11
  100. data/lib/nokogiri/xml/namespace.rb +6 -0
  101. data/lib/nokogiri/xml/node.rb +33 -15
  102. data/lib/nokogiri/xml/node_set.rb +66 -44
  103. data/lib/nokogiri/xml/pp.rb +2 -0
  104. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  105. data/lib/nokogiri/xml/pp/node.rb +56 -0
  106. data/lib/nokogiri/xml/reader.rb +8 -0
  107. data/lib/nokogiri/xml/sax.rb +1 -1
  108. data/lib/nokogiri/xml/sax/document.rb +18 -1
  109. data/lib/nokogiri/xml/sax/parser.rb +15 -8
  110. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  111. data/lib/nokogiri/xml/sax/push_parser.rb +0 -3
  112. data/lib/nokogiri/xml/syntax_error.rb +4 -0
  113. data/lib/nokogiri/xslt/stylesheet.rb +1 -1
  114. data/test/css/test_nthiness.rb +1 -1
  115. data/test/css/test_parser.rb +1 -1
  116. data/test/css/test_tokenizer.rb +1 -1
  117. data/test/css/test_xpath_visitor.rb +1 -1
  118. data/test/ffi/test_document.rb +1 -1
  119. data/test/files/shift_jis.html +10 -0
  120. data/test/files/staff.dtd +10 -0
  121. data/test/helper.rb +12 -3
  122. data/test/html/sax/test_parser.rb +1 -1
  123. data/test/html/sax/test_parser_context.rb +48 -0
  124. data/test/html/test_builder.rb +8 -2
  125. data/test/html/test_document.rb +23 -1
  126. data/test/html/test_document_encoding.rb +15 -1
  127. data/test/html/test_document_fragment.rb +10 -1
  128. data/test/html/test_element_description.rb +1 -2
  129. data/test/html/test_named_characters.rb +1 -1
  130. data/test/html/test_node.rb +61 -1
  131. data/test/html/test_node_encoding.rb +27 -0
  132. data/test/test_convert_xpath.rb +1 -3
  133. data/test/test_css_cache.rb +1 -1
  134. data/test/test_gc.rb +1 -1
  135. data/test/test_memory_leak.rb +1 -1
  136. data/test/test_nokogiri.rb +3 -3
  137. data/test/test_reader.rb +29 -1
  138. data/test/test_xslt_transforms.rb +1 -1
  139. data/test/xml/node/test_save_options.rb +1 -1
  140. data/test/xml/node/test_subclass.rb +1 -1
  141. data/test/xml/sax/test_parser.rb +64 -3
  142. data/test/xml/sax/test_parser_context.rb +56 -0
  143. data/test/xml/sax/test_push_parser.rb +11 -1
  144. data/test/xml/test_attr.rb +1 -1
  145. data/test/xml/test_attribute_decl.rb +82 -0
  146. data/test/xml/test_builder.rb +95 -1
  147. data/test/xml/test_cdata.rb +1 -1
  148. data/test/xml/test_comment.rb +7 -1
  149. data/test/xml/test_document.rb +147 -6
  150. data/test/xml/test_document_encoding.rb +1 -1
  151. data/test/xml/test_document_fragment.rb +55 -5
  152. data/test/xml/test_dtd.rb +40 -5
  153. data/test/xml/test_dtd_encoding.rb +3 -1
  154. data/test/xml/test_element_content.rb +56 -0
  155. data/test/xml/test_element_decl.rb +73 -0
  156. data/test/xml/test_entity_decl.rb +83 -0
  157. data/test/xml/test_entity_reference.rb +1 -1
  158. data/test/xml/test_namespace.rb +21 -1
  159. data/test/xml/test_node.rb +70 -4
  160. data/test/xml/test_node_attributes.rb +1 -1
  161. data/test/xml/test_node_encoding.rb +1 -1
  162. data/test/xml/test_node_set.rb +136 -2
  163. data/test/xml/test_parse_options.rb +1 -1
  164. data/test/xml/test_processing_instruction.rb +1 -1
  165. data/test/xml/test_reader_encoding.rb +1 -1
  166. data/test/xml/test_relax_ng.rb +1 -1
  167. data/test/xml/test_schema.rb +1 -1
  168. data/test/xml/test_syntax_error.rb +27 -0
  169. data/test/xml/test_text.rb +13 -1
  170. data/test/xml/test_unparented_node.rb +1 -1
  171. data/test/xml/test_xpath.rb +1 -1
  172. metadata +57 -40
  173. data/ext/nokogiri/html_sax_parser.c +0 -57
  174. data/ext/nokogiri/html_sax_parser.h +0 -11
  175. data/lib/action-nokogiri.rb +0 -38
  176. data/lib/nokogiri/decorators.rb +0 -2
  177. data/lib/nokogiri/decorators/hpricot.rb +0 -3
  178. data/lib/nokogiri/decorators/hpricot/node.rb +0 -56
  179. data/lib/nokogiri/decorators/hpricot/node_set.rb +0 -54
  180. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +0 -30
  181. data/lib/nokogiri/ffi/html/sax/parser.rb +0 -21
  182. data/lib/nokogiri/hpricot.rb +0 -92
  183. data/lib/nokogiri/xml/entity_declaration.rb +0 -11
  184. data/lib/nokogiri/xml/sax/legacy_handlers.rb +0 -65
  185. data/test/hpricot/files/basic.xhtml +0 -17
  186. data/test/hpricot/files/boingboing.html +0 -2266
  187. data/test/hpricot/files/cy0.html +0 -3653
  188. data/test/hpricot/files/immob.html +0 -400
  189. data/test/hpricot/files/pace_application.html +0 -1320
  190. data/test/hpricot/files/tenderlove.html +0 -16
  191. data/test/hpricot/files/uswebgen.html +0 -220
  192. data/test/hpricot/files/utf8.html +0 -1054
  193. data/test/hpricot/files/week9.html +0 -1723
  194. data/test/hpricot/files/why.xml +0 -19
  195. data/test/hpricot/load_files.rb +0 -11
  196. data/test/hpricot/test_alter.rb +0 -68
  197. data/test/hpricot/test_builder.rb +0 -20
  198. data/test/hpricot/test_parser.rb +0 -350
  199. data/test/hpricot/test_paths.rb +0 -15
  200. data/test/hpricot/test_preserved.rb +0 -77
  201. data/test/hpricot/test_xml.rb +0 -30
@@ -1,11 +1,11 @@
1
1
  module Nokogiri
2
2
  module XML
3
- class Text < Node
3
+ class Text < CharacterData
4
4
 
5
5
  def self.new(string, document, *rest) # :nodoc:
6
6
  node_ptr = LibXML.xmlNewText(string)
7
7
  node_cstruct = LibXML::XmlNode.new(node_ptr)
8
- node_cstruct[:doc] = document.cstruct
8
+ node_cstruct[:doc] = document.cstruct[:doc]
9
9
 
10
10
  node = Node.wrap(node_cstruct, self)
11
11
  node.send :initialize, string, document, *rest
@@ -1,6 +1,7 @@
1
1
  require 'nokogiri/html/entity_lookup'
2
2
  require 'nokogiri/html/document'
3
3
  require 'nokogiri/html/document_fragment'
4
+ require 'nokogiri/html/sax/parser_context'
4
5
  require 'nokogiri/html/sax/parser'
5
6
  require 'nokogiri/html/element_description'
6
7
 
@@ -1,39 +1,54 @@
1
1
  module Nokogiri
2
2
  module HTML
3
3
  class Document < Nokogiri::XML::Document
4
+ ###
5
+ # Get the meta tag encoding for this document. If there is no meta tag,
6
+ # then nil is returned
7
+ def meta_encoding
8
+ return nil unless meta = css('meta').find { |node|
9
+ node['http-equiv'] =~ /Content-Type/i
10
+ }
4
11
 
5
- def initialize *args
6
- super
12
+ /charset\s*=\s*([\w\d-]+)/i.match(meta['content'])[1]
7
13
  end
8
14
 
9
- ####
10
- # Serialize this Document with +encoding+ using +options+
11
- def serialize *args
12
- if args.first && !args.first.is_a?(Hash)
13
- $stderr.puts(<<-eowarn)
14
- #{self.class}#serialize(encoding, save_opts) is deprecated and will be removed in
15
- Nokogiri version 1.4.0 *or* after June 1 2009.
16
- You called serialize from here:
17
-
18
- #{caller.join("\n")}
15
+ ###
16
+ # Set the meta tag encoding for this document. If there is no meta
17
+ # content tag, nil is returned and the encoding is not set.
18
+ def meta_encoding= encoding
19
+ return nil unless meta = css('meta').find { |node|
20
+ node['http-equiv'] =~ /Content-Type/i
21
+ }
19
22
 
20
- Please change to #{self.class}#serialize(:encoding => enc, :save_with => opts)
21
- eowarn
22
- end
23
+ meta['content'] = "text/html; charset=%s" % encoding
24
+ encoding
25
+ end
23
26
 
24
- options = args.first.is_a?(Hash) ? args.shift : {
25
- :encoding => args[0],
26
- :save_with => args[1] || XML::Node::SaveOptions::FORMAT |
27
+ ####
28
+ # Serialize Node using +options+. Save options can also be set using a
29
+ # block. See SaveOptions.
30
+ #
31
+ # These two statements are equivalent:
32
+ #
33
+ # node.serialize(:encoding => 'UTF-8', :save_with => FORMAT | AS_XML)
34
+ #
35
+ # or
36
+ #
37
+ # node.serialize(:encoding => 'UTF-8') do |config|
38
+ # config.format.as_xml
39
+ # end
40
+ #
41
+ def serialize options = {}, &block
42
+ options[:save_with] ||= XML::Node::SaveOptions::FORMAT |
27
43
  XML::Node::SaveOptions::AS_HTML |
28
44
  XML::Node::SaveOptions::NO_DECLARATION |
29
45
  XML::Node::SaveOptions::NO_EMPTY_TAGS
30
- }
31
- super(options)
46
+ super
32
47
  end
33
48
 
34
49
  ####
35
50
  # Create a Nokogiri::XML::DocumentFragment from +tags+
36
- def fragment tags
51
+ def fragment tags = nil
37
52
  DocumentFragment.new(self, tags)
38
53
  end
39
54
 
@@ -58,13 +73,13 @@ Please change to #{self.class}#serialize(:encoding => enc, :save_with => opts)
58
73
 
59
74
  if string_or_io.respond_to?(:read)
60
75
  url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
61
- return self.read_io(string_or_io, url, encoding, options.to_i)
76
+ return read_io(string_or_io, url, encoding, options.to_i)
62
77
  end
63
78
 
64
79
  # read_memory pukes on empty docs
65
- return self.new if string_or_io.nil? or string_or_io.empty?
80
+ return new if string_or_io.nil? or string_or_io.empty?
66
81
 
67
- self.read_memory(string_or_io, url, encoding, options.to_i)
82
+ read_memory(string_or_io, url, encoding, options.to_i)
68
83
  end
69
84
  end
70
85
 
@@ -31,7 +31,7 @@ module Nokogiri
31
31
  def parse_memory data, encoding = 'UTF-8'
32
32
  raise ArgumentError unless data
33
33
  return unless data.length > 0
34
- native_parse_memory data, encoding
34
+ ParserContext.memory(data, encoding).parse_with self
35
35
  end
36
36
 
37
37
  ###
@@ -40,7 +40,7 @@ module Nokogiri
40
40
  raise ArgumentError unless filename
41
41
  raise Errno::ENOENT unless File.exists?(filename)
42
42
  raise Errno::EISDIR if File.directory?(filename)
43
- native_parse_file filename, encoding
43
+ ParserContext.file(filename, encoding).parse_with self
44
44
  end
45
45
  end
46
46
  end
@@ -0,0 +1,16 @@
1
+ module Nokogiri
2
+ module HTML
3
+ module SAX
4
+ ###
5
+ # Context for HTML SAX parsers. This class is usually not instantiated
6
+ # by the user. Instead, you should be looking at
7
+ # Nokogiri::HTML::SAX::Parser
8
+ class ParserContext < Nokogiri::XML::SAX::ParserContext
9
+ def self.new thing, encoding = 'UTF-8'
10
+ [:read, :close].all? { |x| thing.respond_to?(x) } ? super :
11
+ memory(thing, 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.3.3'
3
+ VERSION = '1.4.0'
4
4
 
5
5
  # More complete version information about libxml
6
6
  VERSION_INFO = {}
@@ -1,7 +1,12 @@
1
+ require 'nokogiri/xml/pp'
1
2
  require 'nokogiri/xml/parse_options'
2
3
  require 'nokogiri/xml/sax'
3
4
  require 'nokogiri/xml/fragment_handler'
4
5
  require 'nokogiri/xml/node'
6
+ require 'nokogiri/xml/attribute_decl'
7
+ require 'nokogiri/xml/element_decl'
8
+ require 'nokogiri/xml/element_content'
9
+ require 'nokogiri/xml/character_data'
5
10
  require 'nokogiri/xml/namespace'
6
11
  require 'nokogiri/xml/attr'
7
12
  require 'nokogiri/xml/dtd'
@@ -16,7 +21,7 @@ require 'nokogiri/xml/xpath_context'
16
21
  require 'nokogiri/xml/builder'
17
22
  require 'nokogiri/xml/reader'
18
23
  require 'nokogiri/xml/notation'
19
- require 'nokogiri/xml/entity_declaration'
24
+ require 'nokogiri/xml/entity_decl'
20
25
  require 'nokogiri/xml/schema'
21
26
  require 'nokogiri/xml/relax_ng'
22
27
 
@@ -4,6 +4,11 @@ module Nokogiri
4
4
  alias :value :content
5
5
  alias :to_s :content
6
6
  alias :content= :value=
7
+
8
+ private
9
+ def inspect_attributes
10
+ [:name, :namespace, :value]
11
+ end
7
12
  end
8
13
  end
9
14
  end
@@ -0,0 +1,18 @@
1
+ module Nokogiri
2
+ module XML
3
+ ###
4
+ # Represents an attribute declaration in a DTD
5
+ class AttributeDecl < Nokogiri::XML::Node
6
+ undef_method :attribute_nodes
7
+ undef_method :attributes
8
+ undef_method :content
9
+ undef_method :namespace
10
+ undef_method :namespace_definitions
11
+ undef_method :line
12
+
13
+ def inspect
14
+ "#<#{self.class.name}:#{sprintf("0x%x", object_id)} #{to_s.inspect}>"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -147,6 +147,53 @@ module Nokogiri
147
147
  #
148
148
  # All other options are still supported with this syntax, including
149
149
  # blocks and extra tag attributes.
150
+ #
151
+ # == Namespaces
152
+ #
153
+ # Namespaces are added similarly to attributes. Nokogiri::XML::Builder
154
+ # assumes that when an attribute starts with "xmlns", it is meant to be
155
+ # a namespace:
156
+ #
157
+ # builder = Nokogiri::XML::Builder.new { |xml|
158
+ # xml.root('xmlns' => 'default', 'xmlns:foo' => 'bar') do
159
+ # xml.tenderlove
160
+ # end
161
+ # }
162
+ # puts builder.to_xml
163
+ #
164
+ # Will output XML like this:
165
+ #
166
+ # <?xml version="1.0"?>
167
+ # <root xmlns:foo="bar" xmlns="default">
168
+ # <tenderlove/>
169
+ # </root>
170
+ #
171
+ # === Referencing declared namespaces
172
+ #
173
+ # Tags that reference non-default namespaces (i.e. a tag "foo:bar") can be
174
+ # built by using the Nokogiri::XML::Builder#[] method.
175
+ #
176
+ # For example:
177
+ #
178
+ # builder = Nokogiri::XML::Builder.new do |xml|
179
+ # xml.root('xmlns:foo' => 'bar') {
180
+ # xml.objects {
181
+ # xml['foo'].object.classy.thing!
182
+ # }
183
+ # }
184
+ # end
185
+ # puts builder.to_xml
186
+ #
187
+ # Will output this XML:
188
+ #
189
+ # <?xml version="1.0"?>
190
+ # <root xmlns:foo="bar">
191
+ # <objects>
192
+ # <foo:object class="classy" id="thing"/>
193
+ # </objects>
194
+ # </root>
195
+ #
196
+ # Note the "foo:object" tag.
150
197
  class Builder
151
198
  # The current Document object being built
152
199
  attr_accessor :doc
@@ -159,6 +206,24 @@ module Nokogiri
159
206
 
160
207
  attr_accessor :arity # :nodoc:
161
208
 
209
+ ###
210
+ # Create a builder with an existing root object. This is for use when
211
+ # you have an existing document that you would like to augment with
212
+ # builder methods. The builder context created will start with the
213
+ # given +root+ node.
214
+ #
215
+ # For example:
216
+ #
217
+ # doc = Nokogiri::XML(open('somedoc.xml'))
218
+ # Nokogiri::XML::Builder.with(doc.at('some_tag')) do |xml|
219
+ # # ... Use normal builder methods here ...
220
+ # xml.awesome # add the "awesome" tag below "some_tag"
221
+ # end
222
+ #
223
+ def self.with root, &block
224
+ builder = self.new({}, root, &block)
225
+ end
226
+
162
227
  ###
163
228
  # Create a new Builder object. +options+ are sent to the top level
164
229
  # Document that is being built.
@@ -168,13 +233,21 @@ module Nokogiri
168
233
  # Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
169
234
  # ...
170
235
  # end
171
- def initialize options = {}, &block
172
- namespace = self.class.name.split('::')
173
- namespace[-1] = 'Document'
174
- @doc = eval(namespace.join('::')).new
175
- @parent = @doc
236
+ def initialize options = {}, root = nil, &block
237
+
238
+ if root
239
+ @doc = root.document
240
+ @parent = root
241
+ else
242
+ namespace = self.class.name.split('::')
243
+ namespace[-1] = 'Document'
244
+ @doc = eval(namespace.join('::')).new
245
+ @parent = @doc
246
+ end
247
+
176
248
  @context = nil
177
249
  @arity = nil
250
+ @ns = nil
178
251
 
179
252
  options.each do |k,v|
180
253
  @doc.send(:"#{k}=", v)
@@ -196,8 +269,7 @@ module Nokogiri
196
269
  ###
197
270
  # Create a Text Node with content of +string+
198
271
  def text string
199
- node = Nokogiri::XML::Text.new(string.to_s, @doc)
200
- insert(node)
272
+ insert @doc.create_text_node string
201
273
  end
202
274
 
203
275
  ###
@@ -207,21 +279,57 @@ module Nokogiri
207
279
  insert(node)
208
280
  end
209
281
 
282
+ ###
283
+ # Build a tag that is associated with namespace +ns+. Raises an
284
+ # ArgumentError if +ns+ has not been defined higher in the tree.
285
+ def [] ns
286
+ @ns = @parent.namespace_definitions.find { |x| x.prefix == ns.to_s }
287
+ return self if @ns
288
+
289
+ @parent.ancestors.each do |a|
290
+ next if a == doc
291
+ @ns = a.namespace_definitions.find { |x| x.prefix == ns.to_s }
292
+ return self if @ns
293
+ end
294
+
295
+ raise ArgumentError, "Namespace #{ns} has not been defined"
296
+ end
297
+
210
298
  ###
211
299
  # Convert this Builder object to XML
212
- def to_xml
213
- @doc.to_xml
300
+ def to_xml(*args)
301
+ @doc.to_xml(*args)
302
+ end
303
+
304
+ ###
305
+ # Append the given raw XML +string+ to the document
306
+ def << string
307
+ @doc.fragment(string).children.each { |x| insert(x) }
214
308
  end
215
309
 
216
310
  def method_missing method, *args, &block # :nodoc:
217
311
  if @context && @context.respond_to?(method)
218
312
  @context.send(method, *args, &block)
219
313
  else
220
- node = Nokogiri::XML::Node.new(method.to_s.sub(/[_!]$/, ''), @doc) { |n|
314
+ node = @doc.create_element(method.to_s.sub(/[_!]$/, '')) { |n|
315
+ # Set up the namespace
316
+ if @ns
317
+ n.namespace = @ns
318
+ @ns = nil
319
+ end
320
+
221
321
  args.each do |arg|
222
322
  case arg
223
323
  when Hash
224
- arg.each { |k,v| n[k.to_s] = v.to_s }
324
+ arg.each { |k,v|
325
+ key = k.to_s
326
+ if key =~ /^xmlns(:\w+)?$/
327
+ ns_name = key.split(":", 2)[1]
328
+ n.add_namespace_definition ns_name, v
329
+ next
330
+ end
331
+ n[k.to_s] = v.to_s
332
+ }
225
333
  else
226
334
  n.content = arg
227
335
  end
@@ -250,7 +358,7 @@ module Nokogiri
250
358
  end
251
359
 
252
360
  class NodeBuilder # :nodoc:
253
- def initialize(node, doc_builder)
361
+ def initialize node, doc_builder
254
362
  @node = node
255
363
  @doc_builder = doc_builder
256
364
  end
@@ -272,7 +380,7 @@ module Nokogiri
272
380
  when /^(.*)=/
273
381
  @node[$1] = args.first
274
382
  else
275
- @node['class'] =
383
+ @node['class'] =
276
384
  ((@node['class'] || '').split(/\s/) + [method.to_s]).join(' ')
277
385
  @node.content = args.first if args.first
278
386
  end
@@ -0,0 +1,7 @@
1
+ module Nokogiri
2
+ module XML
3
+ class CharacterData < Nokogiri::XML::Node
4
+ include Nokogiri::XML::PP::CharacterData
5
+ end
6
+ end
7
+ end
@@ -8,6 +8,31 @@ module Nokogiri
8
8
  # For searching a Document, see Nokogiri::XML::Node#css and
9
9
  # Nokogiri::XML::Node#xpath
10
10
  class Document < Node
11
+ ###
12
+ # Parse an XML file. +thing+ may be a String, or any object that
13
+ # responds to _read_ and _close_ such as an IO, or StringIO.
14
+ # +url+ is resource where this document is located. +encoding+ is the
15
+ # encoding that should be used when processing the document. +options+
16
+ # is a number that sets options in the parser, such as
17
+ # Nokogiri::XML::ParseOptions::RECOVER. See the constants in
18
+ # Nokogiri::XML::ParseOptions.
19
+ def self.parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML, &block
20
+
21
+ options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
22
+ # Give the options to the user
23
+ yield options if block_given?
24
+
25
+ if string_or_io.respond_to?(:read)
26
+ url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
27
+ return read_io(string_or_io, url, encoding, options.to_i)
28
+ end
29
+
30
+ # read_memory pukes on empty docs
31
+ return new if string_or_io.nil? or string_or_io.empty?
32
+
33
+ read_memory(string_or_io, url, encoding, options.to_i)
34
+ end
35
+
11
36
  # A list of Nokogiri::XML::SyntaxError found when parsing a document
12
37
  attr_accessor :errors
13
38
 
@@ -15,6 +40,16 @@ module Nokogiri
15
40
  @decorators = nil
16
41
  end
17
42
 
43
+ # Create an element with +name+
44
+ def create_element name, &block
45
+ Nokogiri::XML::Element.new(name, self, &block)
46
+ end
47
+
48
+ # Create a text node with +text+
49
+ def create_text_node text, &block
50
+ Nokogiri::XML::Text.new(text.to_s, self, &block)
51
+ end
52
+
18
53
  # The name of this document. Always returns "document"
19
54
  def name
20
55
  'document'
@@ -65,17 +100,19 @@ module Nokogiri
65
100
 
66
101
  # Get the hash of namespaces on the root Nokogiri::XML::Node
67
102
  def namespaces
68
- root ? root.collect_namespaces : {}
103
+ root ? root.namespaces : {}
69
104
  end
70
105
 
71
106
  ####
72
107
  # Create a Nokogiri::XML::DocumentFragment from +tags+
73
- def fragment tags
108
+ # Returns an empty fragment if +tags+ is nil.
109
+ def fragment tags = nil
74
110
  DocumentFragment.new(self, tags)
75
111
  end
76
112
 
77
113
  undef_method :swap, :parent, :namespace, :default_namespace=
78
- undef_method :add_namespace_definition
114
+ undef_method :add_namespace_definition, :attributes
115
+ undef_method :namespace_definitions, :line
79
116
 
80
117
  def add_child child
81
118
  if [Node::ELEMENT_NODE, Node::DOCUMENT_FRAG_NODE].include? child.type
@@ -85,33 +122,10 @@ module Nokogiri
85
122
  end
86
123
  alias :<< :add_child
87
124
 
88
- class << self
89
- ###
90
- # Parse an XML file. +thing+ may be a String, or any object that
91
- # responds to _read_ and _close_ such as an IO, or StringIO.
92
- # +url+ is resource where this document is located. +encoding+ is the
93
- # encoding that should be used when processing the document. +options+
94
- # is a number that sets options in the parser, such as
95
- # Nokogiri::XML::ParseOptions::RECOVER. See the constants in
96
- # Nokogiri::XML::ParseOptions.
97
- def parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML, &block
98
-
99
- options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
100
- # Give the options to the user
101
- yield options if block_given?
102
-
103
- if string_or_io.respond_to?(:read)
104
- url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
105
- return self.read_io(string_or_io, url, encoding, options.to_i)
106
- end
107
-
108
- # read_memory pukes on empty docs
109
- return self.new if string_or_io.nil? or string_or_io.empty?
110
-
111
- self.read_memory(string_or_io, url, encoding, options.to_i)
112
- end
125
+ private
126
+ def inspect_attributes
127
+ [:name, :children]
113
128
  end
114
-
115
129
  end
116
130
  end
117
131
  end