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
@@ -42,7 +42,7 @@ module Nokogiri
42
42
  end
43
43
 
44
44
  ###
45
- # Returns the index of the first node in self that is == to +node+. Returns nil if no match is found.
45
+ # Returns the index of the first node in self that is == to +node+. Returns nil if no match is found.
46
46
  def index(node)
47
47
  each_with_index { |member, j| return j if member == node }
48
48
  nil
@@ -257,7 +257,7 @@ module Nokogiri
257
257
  # Wrap this NodeSet with +html+ or the results of the builder in +blk+
258
258
  def wrap(html, &blk)
259
259
  each do |j|
260
- new_parent = document.root.parse(html).first
260
+ new_parent = document.parse(html).first
261
261
  j.add_next_sibling(new_parent)
262
262
  new_parent.add_child(j)
263
263
  end
@@ -30,6 +30,42 @@ module Nokogiri
30
30
  class Reader
31
31
  include Enumerable
32
32
 
33
+ TYPE_NONE = 0
34
+ # Element node type
35
+ TYPE_ELEMENT = 1
36
+ # Attribute node type
37
+ TYPE_ATTRIBUTE = 2
38
+ # Text node type
39
+ TYPE_TEXT = 3
40
+ # CDATA node type
41
+ TYPE_CDATA = 4
42
+ # Entity Reference node type
43
+ TYPE_ENTITY_REFERENCE = 5
44
+ # Entity node type
45
+ TYPE_ENTITY = 6
46
+ # PI node type
47
+ TYPE_PROCESSING_INSTRUCTION = 7
48
+ # Comment node type
49
+ TYPE_COMMENT = 8
50
+ # Document node type
51
+ TYPE_DOCUMENT = 9
52
+ # Document Type node type
53
+ TYPE_DOCUMENT_TYPE = 10
54
+ # Document Fragment node type
55
+ TYPE_DOCUMENT_FRAGMENT = 11
56
+ # Notation node type
57
+ TYPE_NOTATION = 12
58
+ # Whitespace node type
59
+ TYPE_WHITESPACE = 13
60
+ # Significant Whitespace node type
61
+ TYPE_SIGNIFICANT_WHITESPACE = 14
62
+ # Element end node type
63
+ TYPE_END_ELEMENT = 15
64
+ # Entity end node type
65
+ TYPE_END_ENTITY = 16
66
+ # XML Declaration node type
67
+ TYPE_XML_DECLARATION = 17
68
+
33
69
  # A list of errors encountered while parsing
34
70
  attr_accessor :errors
35
71
 
@@ -85,7 +85,9 @@ module Nokogiri
85
85
 
86
86
  ###
87
87
  # Called at the beginning of an element
88
- # +name+ is the name of the tag with +attrs+ as attributes
88
+ # * +name+ is the name of the tag
89
+ # * +attrs+ are an assoc list of namespaces and attributes, e.g.:
90
+ # [ ["xmlns:foo", "http://sample.net"], ["size", "large"] ]
89
91
  def start_element name, attrs = []
90
92
  end
91
93
 
@@ -110,7 +112,7 @@ module Nokogiri
110
112
  [['xmlns', ns_prefix].compact.join(':'), ns_uri]
111
113
  } + attrs.map { |attr|
112
114
  [[attr.prefix, attr.localname].compact.join(':'), attr.value]
113
- }.flatten
115
+ }
114
116
  start_element name, attributes
115
117
  end
116
118
 
@@ -9,8 +9,8 @@ module Nokogiri
9
9
  #
10
10
  # xslt = Nokogiri::XSLT(File.read(ARGV[0]))
11
11
  #
12
- def XSLT stylesheet
13
- XSLT.parse(stylesheet)
12
+ def XSLT stylesheet, modules = {}
13
+ XSLT.parse(stylesheet, modules)
14
14
  end
15
15
  end
16
16
 
@@ -20,11 +20,15 @@ module Nokogiri
20
20
  module XSLT
21
21
  class << self
22
22
  ###
23
- # Parse the stylesheet in +string+
24
- def parse string
23
+ # Parse the stylesheet in +string+, register any +modules+
24
+ def parse string, modules = {}
25
+ modules.each do |url, klass|
26
+ XSLT.register url, klass
27
+ end
28
+
25
29
  Stylesheet.parse_stylesheet_doc(XML.parse(string))
26
30
  end
27
-
31
+
28
32
  ###
29
33
  # Quote parameters in +params+ for stylesheet safety
30
34
  def quote_params params
@@ -6,7 +6,7 @@ module Nokogiri
6
6
  # an XML::Document with a Stylesheet:
7
7
  #
8
8
  # doc = Nokogiri::XML(File.read('some_file.xml'))
9
- # xslt = Nokogir::XSLT(File.read('some_transformer.xslt'))
9
+ # xslt = Nokogiri::XSLT(File.read('some_transformer.xslt'))
10
10
  #
11
11
  # puts xslt.transform(doc)
12
12
  #
@@ -6,6 +6,7 @@ ZLIB = 'zlib-1.2.5'
6
6
  ICONV = 'libiconv-1.13.1'
7
7
  LIBXML = 'libxml2-2.7.7'
8
8
  LIBXSLT = 'libxslt-1.1.26'
9
+ RAKE_COMPILER_PKGCONFIG = File.expand_path(File.join(Dir.pwd, "tmp/cross/lib/pkgconfig/"))
9
10
 
10
11
  ### Build zlib ###
11
12
  file "tmp/cross/download/#{ZLIB}" do |t|
@@ -108,7 +109,7 @@ file "tmp/cross/download/#{LIBXSLT}" do |t|
108
109
 
109
110
  Dir.chdir t.name do
110
111
  # FIXME: need to make the host dynamic
111
- sh "CFLAGS='-DIN_LIBXML' ./configure --host=#{HOST} --target=#{TARGET} --enable-static --disable-shared --prefix=#{CROSS_DIR} --with-libxml-prefix=#{CROSS_DIR} --without-python"
112
+ sh "CFLAGS='-DIN_LIBXML' ./configure --host=#{HOST} --target=#{TARGET} --enable-static --disable-shared --prefix=#{CROSS_DIR} --with-libxml-prefix=#{CROSS_DIR} --without-python --without-crypto"
112
113
  end
113
114
  end
114
115
 
@@ -120,7 +121,7 @@ file 'tmp/cross/bin/xslt-config' => "tmp/cross/download/#{LIBXSLT}" do |t|
120
121
  end
121
122
  ### End build libxslt ###
122
123
 
123
- file 'lib/nokogiri/nokogiri.rb' => 'cross:libxslt' do
124
+ file 'lib/nokogiri/nokogiri.rb' => 'cross:check' do
124
125
  File.open("lib/#{HOE.name}/#{HOE.name}.rb", 'wb') do |f|
125
126
  f.write <<-eoruby
126
127
  require "#{HOE.name}/\#{RUBY_VERSION.sub(/\\.\\d+$/, '')}/#{HOE.name}"
@@ -134,25 +135,43 @@ namespace :cross do
134
135
  task :libxml2 => ['cross:zlib', 'cross:iconv', 'tmp/cross/bin/xml2-config']
135
136
  task :libxslt => ['cross:libxml2', 'tmp/cross/bin/xslt-config']
136
137
 
137
- task :copy_dlls do
138
- Dir['tmp/cross/bin/*.dll'].each do |file|
139
- cp file, "ext/nokogiri"
138
+ task :check => ["cross:libxslt"] do
139
+ unless File.directory?(RAKE_COMPILER_PKGCONFIG)
140
+ raise RuntimeError.new("looks like rake-compiler changed where pkgconfig info is kept. (#{RAKE_COMPILER_PKGCONFIG})")
140
141
  end
141
142
  end
142
143
 
143
- task :file_list => 'cross:copy_dlls' do
144
+ task :file_list do
144
145
  HOE.spec.extensions = []
145
146
  HOE.spec.files += Dir["lib/#{HOE.name}/#{HOE.name}.rb"]
146
147
  HOE.spec.files += Dir["lib/#{HOE.name}/1.{8,9}/#{HOE.name}.so"]
147
- HOE.spec.files += Dir["ext/nokogiri/*.dll"]
148
148
  end
149
149
  end
150
150
 
151
151
  CLOBBER.include("lib/nokogiri/nokogiri.{so,dylib,rb,bundle}")
152
152
  CLOBBER.include("lib/nokogiri/1.{8,9}")
153
- CLOBBER.include("ext/nokogiri/*.dll")
154
153
 
155
154
  if Rake::Task.task_defined?(:cross)
156
155
  Rake::Task[:cross].prerequisites << "lib/nokogiri/nokogiri.rb"
157
156
  Rake::Task[:cross].prerequisites << "cross:file_list"
158
157
  end
158
+
159
+ desc "build a windows gem without all the ceremony."
160
+ task "gem:windows" do
161
+ rake_compiler_config = YAML.load_file("#{ENV['HOME']}/.rake-compiler/config.yml")
162
+
163
+ # check that rake-compiler config contains the right patchlevels of 1.8.6 and 1.9.1. see #279.
164
+ ["1.8.6-p383", "1.9.1-p243"].each do |version|
165
+ majmin, patchlevel = version.split("-")
166
+ rbconfig = "rbconfig-#{majmin}"
167
+ unless rake_compiler_config.key?(rbconfig) && rake_compiler_config[rbconfig] =~ /-#{patchlevel}/
168
+ raise "rake-compiler '#{rbconfig}' not #{patchlevel}. try running 'rake-compiler cross-ruby VERSION=#{version}'"
169
+ end
170
+ end
171
+
172
+ # verify that --export-all is in the 1.9.1 rbconfig. see #279,#374,#375.
173
+ rbconfig_191 = rake_compiler_config["rbconfig-1.9.1"]
174
+ raise "rbconfig #{rbconfig_191} needs --export-all in its DLDFLAGS value" if File.read(rbconfig_191).grep(/CONFIG\["DLDFLAGS"\].*--export-all/).empty?
175
+
176
+ system("env PKG_CONFIG_PATH=#{RAKE_COMPILER_PKGCONFIG} RUBY_CC_VERSION=1.8.6:1.9.1 rake cross native gem") || raise("build failed!")
177
+ end
@@ -142,30 +142,31 @@ module Nokogiri
142
142
 
143
143
  def test_nonstandard_nth_selectors
144
144
  ## These are non standard CSS
145
- assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
146
- assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
147
- assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
148
- assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
149
- assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
150
- assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
151
- assert_xpath '//a[node()]', @parser.parse('a:parent')
145
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
146
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
147
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
148
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
149
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
150
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
151
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
152
152
  end
153
153
 
154
154
  def test_standard_nth_selectors
155
- assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
156
- assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
157
- assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
158
- assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
159
- assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
160
- assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
161
- assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
155
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
156
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
157
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
158
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
159
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
160
+ assert_xpath '//a[position() = last()]', @parser.parse('a:nth-last-of-type(1)')
161
+ assert_xpath '//a[position() = last() - 98]', @parser.parse('a:nth-last-of-type(99)')
162
162
  end
163
163
 
164
164
  def test_nth_child_selectors
165
- assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
166
- assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
167
- assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
168
- assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
165
+ assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
166
+ assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
167
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
168
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:nth-last-child(1)')
169
+ assert_xpath '//*[position() = last() - 98 and self::a]', @parser.parse('a:nth-last-child(99)')
169
170
  end
170
171
 
171
172
  def test_miscellaneous_selectors
@@ -185,6 +186,16 @@ module Nokogiri
185
186
  assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
186
187
  assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
187
188
  assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
189
+
190
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(2n)')
191
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(2n+1)')
192
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(even)')
193
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(odd)')
194
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 4) = 0)]', @parser.parse('a:nth-last-of-type(4n+3)')
195
+ assert_xpath '//a[((last()-position()+1) <= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(-1n+3)')
196
+ assert_xpath '//a[((last()-position()+1) <= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(-n+3)')
197
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(1n+3)')
198
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(n+3)')
188
199
  end
189
200
 
190
201
  def test_preceding_selector
@@ -0,0 +1,16 @@
1
+ require "helper"
2
+
3
+ module Nokogiri
4
+ class TestSlop < Nokogiri::TestCase
5
+ def test_description_tag
6
+ doc = Nokogiri.Slop(<<-eoxml)
7
+ <item>
8
+ <title>foo</title>
9
+ <description>this is the foo thing</description>
10
+ </item>
11
+ eoxml
12
+ assert doc.item.title
13
+ assert doc.item._description, 'should have description'
14
+ end
15
+ end
16
+ end
@@ -74,6 +74,16 @@ module Nokogiri
74
74
  assert Nokogiri::HTML::DocumentFragment.new(@html)
75
75
  end
76
76
 
77
+ def test_body_fragment_should_contain_body
78
+ fragment = Nokogiri::HTML::DocumentFragment.parse(" <body><div>foo</div></body>")
79
+ assert_match(/^<body>/, fragment.to_s)
80
+ end
81
+
82
+ def test_nonbody_fragment_should_not_contain_body
83
+ fragment = Nokogiri::HTML::DocumentFragment.parse("<div>foo</div>")
84
+ assert_match(/^<div>/, fragment.to_s)
85
+ end
86
+
77
87
  def test_fragment_should_have_document
78
88
  fragment = Nokogiri::HTML::DocumentFragment.new(@html)
79
89
  assert_equal @html, fragment.document
@@ -140,13 +150,13 @@ module Nokogiri
140
150
  def test_html_fragment_with_leading_whitespace
141
151
  doc = " <div>b</div> "
142
152
  fragment = Nokogiri::HTML::Document.new.fragment(doc)
143
- assert_equal "<div>b</div>", fragment.to_s
153
+ assert_match %r% <div>b</div> *%, fragment.to_s
144
154
  end
145
155
 
146
156
  def test_html_fragment_with_leading_whitespace_and_newline
147
157
  doc = " \n<div>b</div> "
148
158
  fragment = Nokogiri::HTML::Document.new.fragment(doc)
149
- assert_equal "<div>b</div>", fragment.to_s
159
+ assert_match %r% \n<div>b</div> *%, fragment.to_s
150
160
  end
151
161
 
152
162
  def test_html_fragment_with_leading_text_and_newline
@@ -156,7 +166,7 @@ module Nokogiri
156
166
 
157
167
  def test_html_fragment_with_leading_whitespace_and_text_and_newline
158
168
  fragment = HTML::Document.new.fragment(" First line\nSecond line<br>Broken line")
159
- assert_equal "First line\nSecond line<br>Broken line", fragment.to_s
169
+ assert_equal " First line\nSecond line<br>Broken line", fragment.to_s
160
170
  end
161
171
 
162
172
  def test_html_fragment_with_leading_entity
@@ -207,6 +217,39 @@ module Nokogiri
207
217
  assert_equal("<p>hello<!-- your ad here --></p>",
208
218
  fragment.to_s)
209
219
  end
220
+
221
+ def test_malformed_fragment_is_corrected
222
+ fragment = HTML::DocumentFragment.parse("<div </div>")
223
+ assert_equal "<div></div>", fragment.to_s
224
+ end
225
+
226
+ def test_unclosed_script_tag
227
+ # see GH#315
228
+ fragment = HTML::DocumentFragment.parse("foo <script>bar")
229
+ assert_equal "foo <script>bar</script>", fragment.to_html
230
+ end
231
+
232
+ def test_error_propagation_on_fragment_parse
233
+ frag = Nokogiri::HTML::DocumentFragment.parse "<hello>oh, hello there.</hello>"
234
+ assert frag.errors.any?{|err| err.to_s =~ /Tag hello invalid/}, "errors should be copied to the fragment"
235
+ end
236
+
237
+ def test_error_propagation_on_fragment_parse_in_node_context
238
+ doc = Nokogiri::HTML::Document.parse "<html><body><div></div></body></html>"
239
+ context_node = doc.at_css "div"
240
+ frag = Nokogiri::HTML::DocumentFragment.new doc, "<hello>oh, hello there.</hello>", context_node
241
+ assert frag.errors.any?{|err| err.to_s =~ /Tag hello invalid/}, "errors should be on the context node's document"
242
+ end
243
+
244
+ def test_error_propagation_on_fragment_parse_in_node_context_should_not_include_preexisting_errors
245
+ doc = Nokogiri::HTML::Document.parse "<html><body><div></div><jimmy></jimmy></body></html>"
246
+ assert doc.errors.any?{|err| err.to_s =~ /jimmy/}, "assert on setup"
247
+
248
+ context_node = doc.at_css "div"
249
+ frag = Nokogiri::HTML::DocumentFragment.new doc, "<hello>oh, hello there.</hello>", context_node
250
+ assert frag.errors.any?{|err| err.to_s =~ /Tag hello invalid/}, "errors should be on the context node's document"
251
+ assert frag.errors.none?{|err| err.to_s =~ /jimmy/}, "errors should not include pre-existing document errors"
252
+ end
210
253
  end
211
254
  end
212
255
  end
@@ -127,6 +127,15 @@ module Nokogiri
127
127
  assert_equal 'foo&bar&baz', node['href']
128
128
  end
129
129
 
130
+ def test_parse_config_option
131
+ node = @html.at('div')
132
+ options = nil
133
+ node.parse("<div></div>") do |config|
134
+ options = config
135
+ end
136
+ assert_equal Nokogiri::XML::ParseOptions::DEFAULT_HTML, options.to_i
137
+ end
138
+
130
139
  def test_fragment_handler_does_not_regurge_on_invalid_attributes
131
140
  iframe = %Q{<iframe style="width: 0%; height: 0px" src="http://someurl" allowtransparency></iframe>}
132
141
  assert_nothing_raised { @html.at('div').fragment(iframe) }
@@ -24,7 +24,7 @@ module Nokogiri
24
24
 
25
25
  assert block_called
26
26
 
27
- assert_equal ['a', '&b'], doc.start_elements.first.last
27
+ assert_equal [['foo', [['a', '&b']]]], doc.start_elements
28
28
  end
29
29
 
30
30
  def test_parser_context_yielded_in_memory
@@ -40,7 +40,7 @@ module Nokogiri
40
40
 
41
41
  assert block_called
42
42
 
43
- assert_equal ['a', '&b'], doc.start_elements.first.last
43
+ assert_equal [['foo', [['a', '&b']]]], doc.start_elements
44
44
  end
45
45
 
46
46
  def test_xml_decl
@@ -296,7 +296,15 @@ module Nokogiri
296
296
  @parser.parse_memory(<<-eoxml)
297
297
  <p id="asdfasdf">Paragraph 1</p>
298
298
  eoxml
299
- assert_equal [["p", ["id", "asdfasdf"]]],
299
+ assert_equal [["p", [["id", "asdfasdf"]]]],
300
+ @parser.document.start_elements
301
+ end
302
+
303
+ def test_start_element_attrs_include_namespaces
304
+ @parser.parse_memory(<<-eoxml)
305
+ <p xmlns:foo='http://foo.example.com/'>Paragraph 1</p>
306
+ eoxml
307
+ assert_equal [["p", [['xmlns:foo', 'http://foo.example.com/']]]],
300
308
  @parser.document.start_elements
301
309
  end
302
310
 
@@ -6,6 +6,56 @@ module Nokogiri
6
6
  module XML
7
7
  module SAX
8
8
  class TestParserContext < Nokogiri::SAX::TestCase
9
+ def setup
10
+ @xml = '<hello>
11
+
12
+ world
13
+ <inter>
14
+ <net>
15
+ </net>
16
+ </inter>
17
+
18
+ </hello>'
19
+ end
20
+
21
+ class Counter < Nokogiri::XML::SAX::Document
22
+ attr_accessor :context, :lines, :columns
23
+ def initialize
24
+ @context = nil
25
+ @lines = []
26
+ @columns = []
27
+ end
28
+
29
+ def start_element name, attrs = []
30
+ @lines << [name, context.line]
31
+ @columns << [name, context.column]
32
+ end
33
+ end
34
+
35
+ def test_line_numbers
36
+ sax_handler = Counter.new
37
+
38
+ parser = Nokogiri::XML::SAX::Parser.new(sax_handler)
39
+ parser.parse(@xml) do |ctx|
40
+ sax_handler.context = ctx
41
+ end
42
+
43
+ assert_equal [["hello", 1], ["inter", 4], ["net", 5]],
44
+ sax_handler.lines
45
+ end
46
+
47
+ def test_column_numbers
48
+ sax_handler = Counter.new
49
+
50
+ parser = Nokogiri::XML::SAX::Parser.new(sax_handler)
51
+ parser.parse(@xml) do |ctx|
52
+ sax_handler.context = ctx
53
+ end
54
+
55
+ assert_equal [["hello", 7], ["inter", 7], ["net", 9]],
56
+ sax_handler.columns
57
+ end
58
+
9
59
  def test_replace_entities
10
60
  pc = ParserContext.new StringIO.new('<root />'), 'UTF-8'
11
61
  pc.replace_entities = false