nokogiri 1.16.8 → 1.18.1

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -22
  3. data/LICENSE-DEPENDENCIES.md +6 -6
  4. data/README.md +8 -5
  5. data/dependencies.yml +6 -6
  6. data/ext/nokogiri/extconf.rb +188 -142
  7. data/ext/nokogiri/gumbo.c +69 -53
  8. data/ext/nokogiri/html4_document.c +10 -4
  9. data/ext/nokogiri/html4_element_description.c +18 -18
  10. data/ext/nokogiri/html4_sax_parser.c +40 -0
  11. data/ext/nokogiri/html4_sax_parser_context.c +48 -58
  12. data/ext/nokogiri/html4_sax_push_parser.c +25 -24
  13. data/ext/nokogiri/libxml2_polyfill.c +114 -0
  14. data/ext/nokogiri/nokogiri.c +9 -2
  15. data/ext/nokogiri/nokogiri.h +18 -33
  16. data/ext/nokogiri/xml_attr.c +1 -1
  17. data/ext/nokogiri/xml_cdata.c +2 -10
  18. data/ext/nokogiri/xml_comment.c +3 -8
  19. data/ext/nokogiri/xml_document.c +163 -156
  20. data/ext/nokogiri/xml_document_fragment.c +10 -25
  21. data/ext/nokogiri/xml_dtd.c +1 -1
  22. data/ext/nokogiri/xml_element_content.c +9 -9
  23. data/ext/nokogiri/xml_encoding_handler.c +4 -4
  24. data/ext/nokogiri/xml_namespace.c +6 -6
  25. data/ext/nokogiri/xml_node.c +134 -103
  26. data/ext/nokogiri/xml_node_set.c +46 -44
  27. data/ext/nokogiri/xml_reader.c +54 -58
  28. data/ext/nokogiri/xml_relax_ng.c +35 -56
  29. data/ext/nokogiri/xml_sax_parser.c +156 -88
  30. data/ext/nokogiri/xml_sax_parser_context.c +219 -131
  31. data/ext/nokogiri/xml_sax_push_parser.c +68 -49
  32. data/ext/nokogiri/xml_schema.c +50 -85
  33. data/ext/nokogiri/xml_syntax_error.c +19 -11
  34. data/ext/nokogiri/xml_text.c +2 -4
  35. data/ext/nokogiri/xml_xpath_context.c +103 -100
  36. data/ext/nokogiri/xslt_stylesheet.c +8 -8
  37. data/gumbo-parser/src/ascii.c +2 -2
  38. data/gumbo-parser/src/error.c +76 -48
  39. data/gumbo-parser/src/error.h +5 -1
  40. data/gumbo-parser/src/nokogiri_gumbo.h +11 -2
  41. data/gumbo-parser/src/parser.c +63 -25
  42. data/gumbo-parser/src/tokenizer.c +6 -6
  43. data/lib/nokogiri/class_resolver.rb +1 -1
  44. data/lib/nokogiri/css/node.rb +6 -2
  45. data/lib/nokogiri/css/parser.rb +6 -4
  46. data/lib/nokogiri/css/parser.y +2 -2
  47. data/lib/nokogiri/css/parser_extras.rb +6 -66
  48. data/lib/nokogiri/css/selector_cache.rb +38 -0
  49. data/lib/nokogiri/css/tokenizer.rb +4 -4
  50. data/lib/nokogiri/css/tokenizer.rex +9 -8
  51. data/lib/nokogiri/css/xpath_visitor.rb +42 -6
  52. data/lib/nokogiri/css.rb +86 -20
  53. data/lib/nokogiri/decorators/slop.rb +3 -5
  54. data/lib/nokogiri/encoding_handler.rb +2 -2
  55. data/lib/nokogiri/html4/document.rb +44 -23
  56. data/lib/nokogiri/html4/document_fragment.rb +124 -12
  57. data/lib/nokogiri/html4/encoding_reader.rb +1 -1
  58. data/lib/nokogiri/html4/sax/parser.rb +23 -38
  59. data/lib/nokogiri/html4/sax/parser_context.rb +4 -9
  60. data/lib/nokogiri/html4.rb +9 -14
  61. data/lib/nokogiri/html5/builder.rb +40 -0
  62. data/lib/nokogiri/html5/document.rb +61 -30
  63. data/lib/nokogiri/html5/document_fragment.rb +130 -20
  64. data/lib/nokogiri/html5/node.rb +4 -4
  65. data/lib/nokogiri/html5.rb +114 -72
  66. data/lib/nokogiri/version/constant.rb +1 -1
  67. data/lib/nokogiri/xml/builder.rb +8 -1
  68. data/lib/nokogiri/xml/document.rb +70 -26
  69. data/lib/nokogiri/xml/document_fragment.rb +84 -13
  70. data/lib/nokogiri/xml/node.rb +82 -11
  71. data/lib/nokogiri/xml/node_set.rb +9 -7
  72. data/lib/nokogiri/xml/parse_options.rb +1 -1
  73. data/lib/nokogiri/xml/pp/node.rb +6 -1
  74. data/lib/nokogiri/xml/reader.rb +46 -13
  75. data/lib/nokogiri/xml/relax_ng.rb +57 -20
  76. data/lib/nokogiri/xml/sax/document.rb +174 -83
  77. data/lib/nokogiri/xml/sax/parser.rb +115 -41
  78. data/lib/nokogiri/xml/sax/parser_context.rb +116 -8
  79. data/lib/nokogiri/xml/sax/push_parser.rb +3 -0
  80. data/lib/nokogiri/xml/sax.rb +48 -0
  81. data/lib/nokogiri/xml/schema.rb +112 -45
  82. data/lib/nokogiri/xml/searchable.rb +38 -42
  83. data/lib/nokogiri/xml/syntax_error.rb +22 -0
  84. data/lib/nokogiri/xml/xpath_context.rb +14 -3
  85. data/lib/nokogiri/xml.rb +13 -24
  86. data/lib/nokogiri/xslt.rb +3 -9
  87. data/lib/xsd/xmlparser/nokogiri.rb +3 -4
  88. data/patches/libxml2/0019-xpath-Use-separate-static-hash-table-for-standard-fu.patch +244 -0
  89. data/ports/archives/libxml2-2.13.5.tar.xz +0 -0
  90. data/ports/archives/libxslt-1.1.42.tar.xz +0 -0
  91. metadata +13 -12
  92. data/ext/nokogiri/libxml2_backwards_compat.c +0 -121
  93. data/patches/libxml2/0003-libxml2.la-is-in-top_builddir.patch +0 -25
  94. data/ports/archives/libxml2-2.12.9.tar.xz +0 -0
  95. data/ports/archives/libxslt-1.1.39.tar.xz +0 -0
@@ -4,15 +4,123 @@ module Nokogiri
4
4
  module XML
5
5
  module SAX
6
6
  ###
7
- # Context for XML SAX parsers. This class is usually not instantiated
8
- # by the user. Instead, you should be looking at
9
- # Nokogiri::XML::SAX::Parser
7
+ # Context object to invoke the XML SAX parser on the SAX::Document handler.
8
+ #
9
+ # 💡 This class is usually not instantiated by the user. Use Nokogiri::XML::SAX::Parser
10
+ # instead.
10
11
  class ParserContext
11
- def self.new(thing, encoding = "UTF-8")
12
- if [:read, :close].all? { |x| thing.respond_to?(x) }
13
- io(thing, Parser::ENCODINGS[encoding])
14
- else
15
- memory(thing)
12
+ class << self
13
+ ###
14
+ # :call-seq:
15
+ # new(input)
16
+ # new(input, encoding)
17
+ #
18
+ # Create a parser context for an IO or a String. This is a shorthand method for
19
+ # ParserContext.io and ParserContext.memory.
20
+ #
21
+ # [Parameters]
22
+ # - +input+ (IO, String) A String or a readable IO object
23
+ # - +encoding+ (optional) (Encoding) The +Encoding+ to use, or the name of an
24
+ # encoding to use (default +nil+, encoding will be autodetected)
25
+ #
26
+ # If +input+ quacks like a readable IO object, this method forwards to ParserContext.io,
27
+ # otherwise it forwards to ParserContext.memory.
28
+ #
29
+ # [Returns] Nokogiri::XML::SAX::ParserContext
30
+ #
31
+ def new(input, encoding = nil)
32
+ if [:read, :close].all? { |x| input.respond_to?(x) }
33
+ io(input, encoding)
34
+ else
35
+ memory(input, encoding)
36
+ end
37
+ end
38
+
39
+ ###
40
+ # :call-seq:
41
+ # io(input)
42
+ # io(input, encoding)
43
+ #
44
+ # Create a parser context for an +input+ IO which will assume +encoding+
45
+ #
46
+ # [Parameters]
47
+ # - +io+ (IO) The readable IO object from which to read input
48
+ # - +encoding+ (optional) (Encoding) The +Encoding+ to use, or the name of an
49
+ # encoding to use (default +nil+, encoding will be autodetected)
50
+ #
51
+ # [Returns] Nokogiri::XML::SAX::ParserContext
52
+ #
53
+ # 💡 Calling this method directly is discouraged. Use Nokogiri::XML::SAX::Parser parse
54
+ # methods which are more convenient for most use cases.
55
+ #
56
+ def io(input, encoding = nil)
57
+ native_io(input, resolve_encoding(encoding))
58
+ end
59
+
60
+ ###
61
+ # :call-seq:
62
+ # memory(input)
63
+ # memory(input, encoding)
64
+ #
65
+ # Create a parser context for the +input+ String.
66
+ #
67
+ # [Parameters]
68
+ # - +input+ (String) The input string to be parsed.
69
+ # - +encoding+ (optional) (Encoding, String) The +Encoding+ to use, or the name of an encoding to
70
+ # use (default +nil+, encoding will be autodetected)
71
+ #
72
+ # [Returns] Nokogiri::XML::SAX::ParserContext
73
+ #
74
+ # 💡 Calling this method directly is discouraged. Use Nokogiri::XML::SAX::Parser parse methods
75
+ # which are more convenient for most use cases.
76
+ #
77
+ def memory(input, encoding = nil)
78
+ native_memory(input, resolve_encoding(encoding))
79
+ end
80
+
81
+ ###
82
+ # :call-seq:
83
+ # file(path)
84
+ # file(path, encoding)
85
+ #
86
+ # Create a parser context for the file at +path+.
87
+ #
88
+ # [Parameters]
89
+ # - +path+ (String) The path to the input file
90
+ # - +encoding+ (optional) (Encoding, String) The +Encoding+ to use, or the name of an encoding to
91
+ # use (default +nil+, encoding will be autodetected)
92
+ #
93
+ # [Returns] Nokogiri::XML::SAX::ParserContext
94
+ #
95
+ # 💡 Calling this method directly is discouraged. Use Nokogiri::XML::SAX::Parser.parse_file which
96
+ # is more convenient for most use cases.
97
+ def file(input, encoding = nil)
98
+ native_file(input, resolve_encoding(encoding))
99
+ end
100
+
101
+ private def resolve_encoding(encoding)
102
+ case encoding
103
+ when Encoding
104
+ encoding
105
+
106
+ when nil
107
+ nil # totally fine, parser will guess encoding
108
+
109
+ when Integer
110
+ warn("Passing an integer to Nokogiri::XML::SAX::ParserContext.io is deprecated. Use an Encoding object instead. This will become an error in a future release.", uplevel: 2, category: :deprecated)
111
+
112
+ return nil if encoding == Parser::ENCODINGS["NONE"]
113
+
114
+ encoding = Parser::REVERSE_ENCODINGS[encoding]
115
+ raise ArgumentError, "Invalid libxml2 encoding id #{encoding}" if encoding.nil?
116
+ Encoding.find(encoding)
117
+
118
+ when String
119
+ Encoding.find(encoding)
120
+
121
+ else
122
+ raise ArgumentError, "Cannot resolve #{encoding.inspect} to an Encoding"
123
+ end
16
124
  end
17
125
  end
18
126
  end
@@ -52,6 +52,9 @@ module Nokogiri
52
52
  ###
53
53
  # Finish the parsing. This method is only necessary for
54
54
  # Nokogiri::XML::SAX::Document#end_document to be called.
55
+ #
56
+ # ⚠ Note that empty documents are treated as an error when using the libxml2-based
57
+ # implementation (CRuby), but are fine when using the Xerces-based implementation (JRuby).
55
58
  def finish
56
59
  write("", true)
57
60
  end
@@ -1,5 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ module Nokogiri
4
+ module XML
5
+ ###
6
+ # SAX Parsers are event-driven parsers.
7
+ #
8
+ # Two SAX parsers for XML are available, a parser that reads from a string or IO object as it
9
+ # feels necessary, and a parser that you explicitly feed XML in chunks. If you want to let
10
+ # Nokogiri deal with reading your XML, use the Nokogiri::XML::SAX::Parser. If you want to have
11
+ # fine grain control over the XML input, use the Nokogiri::XML::SAX::PushParser.
12
+ #
13
+ # If you want to do SAX style parsing of HTML, check out Nokogiri::HTML4::SAX.
14
+ #
15
+ # The basic way a SAX style parser works is by creating a parser, telling the parser about the
16
+ # events we're interested in, then giving the parser some XML to process. The parser will notify
17
+ # you when it encounters events you said you would like to know about.
18
+ #
19
+ # To register for events, subclass Nokogiri::XML::SAX::Document and implement the methods for
20
+ # which you would like notification.
21
+ #
22
+ # For example, if I want to be notified when a document ends, and when an element starts, I
23
+ # would write a class like this:
24
+ #
25
+ # class MyHandler < Nokogiri::XML::SAX::Document
26
+ # def end_document
27
+ # puts "the document has ended"
28
+ # end
29
+ #
30
+ # def start_element name, attributes = []
31
+ # puts "#{name} started"
32
+ # end
33
+ # end
34
+ #
35
+ # Then I would instantiate a SAX parser with this document, and feed the parser some XML
36
+ #
37
+ # # Create a new parser
38
+ # parser = Nokogiri::XML::SAX::Parser.new(MyHandler.new)
39
+ #
40
+ # # Feed the parser some XML
41
+ # parser.parse(File.open(ARGV[0]))
42
+ #
43
+ # Now my document handler will be called when each node starts, and when then document ends. To
44
+ # see what kinds of events are available, take a look at Nokogiri::XML::SAX::Document.
45
+ #
46
+ module SAX
47
+ end
48
+ end
49
+ end
50
+
3
51
  require_relative "sax/document"
4
52
  require_relative "sax/parser_context"
5
53
  require_relative "sax/parser"
@@ -3,70 +3,137 @@
3
3
  module Nokogiri
4
4
  module XML
5
5
  class << self
6
- ###
7
- # Create a new Nokogiri::XML::Schema object using a +string_or_io+
8
- # object.
9
- def Schema(string_or_io, options = ParseOptions::DEFAULT_SCHEMA)
10
- Schema.new(string_or_io, options)
6
+ # :call-seq:
7
+ # Schema(input) Nokogiri::XML::Schema
8
+ # Schema(input, parse_options) → Nokogiri::XML::Schema
9
+ #
10
+ # Convenience method for Nokogiri::XML::Schema.new
11
+ def Schema(...)
12
+ Schema.new(...)
11
13
  end
12
14
  end
13
15
 
14
- ###
15
- # Nokogiri::XML::Schema is used for validating XML against a schema
16
- # (usually from an xsd file).
16
+ # Nokogiri::XML::Schema is used for validating \XML against an \XSD schema definition.
17
17
  #
18
- # == Synopsis
18
+ # Since v1.11.0, Schema treats inputs as *untrusted* by default, and so external entities are
19
+ # not resolved from the network (+http://+ or +ftp://+). When parsing a trusted document, the
20
+ # caller may turn off the +NONET+ option via the ParseOptions to (re-)enable external entity
21
+ # resolution over a network connection.
19
22
  #
20
- # Validate an XML document against a Schema. Loop over the errors that
21
- # are returned and print them out:
23
+ # 🛡 Before v1.11.0, documents were "trusted" by default during schema parsing which was counter
24
+ # to Nokogiri's "untrusted by default" security policy.
22
25
  #
23
- # xsd = Nokogiri::XML::Schema(File.read(PO_SCHEMA_FILE))
24
- # doc = Nokogiri::XML(File.read(PO_XML_FILE))
26
+ # *Example:* Determine whether an \XML document is valid.
25
27
  #
26
- # xsd.validate(doc).each do |error|
27
- # puts error.message
28
- # end
28
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
29
+ # doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
30
+ # schema.valid?(doc) # Boolean
29
31
  #
30
- # The list of errors are Nokogiri::XML::SyntaxError objects.
32
+ # *Example:* Validate an \XML document against an \XSD schema, and capture any errors that are found.
33
+ #
34
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
35
+ # doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
36
+ # errors = schema.validate(doc) # Array<SyntaxError>
37
+ #
38
+ # *Example:* Validate an \XML document using a Document containing an \XSD schema definition.
39
+ #
40
+ # schema_doc = Nokogiri::XML::Document.parse(File.read(RELAX_NG_FILE))
41
+ # schema = Nokogiri::XML::Schema.from_document(schema_doc)
42
+ # doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
43
+ # schema.valid?(doc) # Boolean
31
44
  #
32
- # NOTE: As of v1.11.0, Schema treats inputs as UNTRUSTED by default, and so external entities
33
- # are not resolved from the network (`http://` or `ftp://`). Previously, parsing treated
34
- # documents as "trusted" by default which was counter to Nokogiri's "untrusted by default"
35
- # security policy. If a document is trusted, then the caller may turn off the NONET option via
36
- # the ParseOptions to re-enable external entity resolution over a network connection.
37
45
  class Schema
38
- # Errors while parsing the schema file
46
+ # The errors found while parsing the \XSD
47
+ #
48
+ # [Returns] Array<Nokogiri::XML::SyntaxError>
39
49
  attr_accessor :errors
40
- # The Nokogiri::XML::ParseOptions used to parse the schema
50
+
51
+ # The options used to parse the schema
52
+ #
53
+ # [Returns] Nokogiri::XML::ParseOptions
41
54
  attr_accessor :parse_options
42
55
 
43
- ###
44
- # Create a new Nokogiri::XML::Schema object using a +string_or_io+
45
- # object.
46
- def self.new(string_or_io, options = ParseOptions::DEFAULT_SCHEMA)
47
- from_document(Nokogiri::XML(string_or_io), options)
56
+ # :call-seq:
57
+ # new(input) Nokogiri::XML::Schema
58
+ # new(input, parse_options) → Nokogiri::XML::Schema
59
+ #
60
+ # Parse an \XSD schema definition from a String or IO to create a new Nokogiri::XML::Schema
61
+ #
62
+ # [Parameters]
63
+ # - +input+ (String | IO) \XSD schema definition
64
+ # - +parse_options+ (Nokogiri::XML::ParseOptions)
65
+ # Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA
66
+ #
67
+ # [Returns] Nokogiri::XML::Schema
68
+ #
69
+ def self.new(input, parse_options_ = ParseOptions::DEFAULT_SCHEMA, parse_options: parse_options_)
70
+ from_document(Nokogiri::XML::Document.parse(input), parse_options)
71
+ end
72
+
73
+ # :call-seq:
74
+ # read_memory(input) → Nokogiri::XML::Schema
75
+ # read_memory(input, parse_options) → Nokogiri::XML::Schema
76
+ #
77
+ # Convenience method for Nokogiri::XML::Schema.new
78
+ def self.read_memory(...)
79
+ # TODO deprecate this method
80
+ new(...)
48
81
  end
49
82
 
50
- ###
51
- # Validate +thing+ against this schema. +thing+ can be a
52
- # Nokogiri::XML::Document object, or a filename. An Array of
53
- # Nokogiri::XML::SyntaxError objects found while validating the
54
- # +thing+ is returned.
55
- def validate(thing)
56
- if thing.is_a?(Nokogiri::XML::Document)
57
- validate_document(thing)
58
- elsif File.file?(thing)
59
- validate_file(thing)
83
+ #
84
+ # :call-seq: validate(input) Array<SyntaxError>
85
+ #
86
+ # Validate +input+ and return any errors that are found.
87
+ #
88
+ # [Parameters]
89
+ # - +input+ (Nokogiri::XML::Document | String)
90
+ # A parsed document, or a string containing a local filename.
91
+ #
92
+ # [Returns] Array<SyntaxError>
93
+ #
94
+ # *Example:* Validate an existing XML::Document, and capture any errors that are found.
95
+ #
96
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
97
+ # errors = schema.validate(document)
98
+ #
99
+ # *Example:* Validate an \XML document on disk, and capture any errors that are found.
100
+ #
101
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
102
+ # errors = schema.validate("/path/to/file.xml")
103
+ #
104
+ def validate(input)
105
+ if input.is_a?(Nokogiri::XML::Document)
106
+ validate_document(input)
107
+ elsif File.file?(input)
108
+ validate_file(input)
60
109
  else
61
- raise ArgumentError, "Must provide Nokogiri::Xml::Document or the name of an existing file"
110
+ raise ArgumentError, "Must provide Nokogiri::XML::Document or the name of an existing file"
62
111
  end
63
112
  end
64
113
 
65
- ###
66
- # Returns true if +thing+ is a valid Nokogiri::XML::Document or
67
- # file.
68
- def valid?(thing)
69
- validate(thing).empty?
114
+ #
115
+ # :call-seq: valid?(input) Boolean
116
+ #
117
+ # Validate +input+ and return a Boolean indicating whether the document is valid
118
+ #
119
+ # [Parameters]
120
+ # - +input+ (Nokogiri::XML::Document | String)
121
+ # A parsed document, or a string containing a local filename.
122
+ #
123
+ # [Returns] Boolean
124
+ #
125
+ # *Example:* Validate an existing XML::Document
126
+ #
127
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
128
+ # return unless schema.valid?(document)
129
+ #
130
+ # *Example:* Validate an \XML document on disk
131
+ #
132
+ # schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
133
+ # return unless schema.valid?("/path/to/file.xml")
134
+ #
135
+ def valid?(input)
136
+ validate(input).empty?
70
137
  end
71
138
  end
72
139
  end
@@ -207,35 +207,26 @@ module Nokogiri
207
207
 
208
208
  private
209
209
 
210
- def css_internal(node, rules, handler, ns)
211
- xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
212
- end
213
-
214
- def xpath_internal(node, paths, handler, ns, binds)
215
- document = node.document
216
- return NodeSet.new(document) unless document
217
-
218
- if paths.length == 1
219
- return xpath_impl(node, paths.first, handler, ns, binds)
210
+ def extract_params(params) # :nodoc:
211
+ handler = params.find do |param|
212
+ ![Hash, String, Symbol].include?(param.class)
220
213
  end
214
+ params -= [handler] if handler
221
215
 
222
- NodeSet.new(document) do |combined|
223
- paths.each do |path|
224
- xpath_impl(node, path, handler, ns, binds).each { |set| combined << set }
225
- end
216
+ hashes = []
217
+ while Hash === params.last || params.last.nil?
218
+ hashes << params.pop
219
+ break if params.empty?
226
220
  end
227
- end
221
+ ns, binds = hashes.reverse
228
222
 
229
- def xpath_impl(node, path, handler, ns, binds)
230
- ctx = XPathContext.new(node)
231
- ctx.register_namespaces(ns)
232
- path = path.gsub("xmlns:", " :") unless Nokogiri.uses_libxml?
223
+ ns ||= document.root&.namespaces || {}
233
224
 
234
- binds&.each do |key, value|
235
- ctx.register_variable(key.to_s, value)
236
- end
225
+ [params, handler, ns, binds]
226
+ end
237
227
 
238
- ctx.evaluate(path, handler)
228
+ def css_internal(node, rules, handler, ns)
229
+ xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
239
230
  end
240
231
 
241
232
  def css_rules_to_xpath(rules, ns)
@@ -243,35 +234,40 @@ module Nokogiri
243
234
  end
244
235
 
245
236
  def xpath_query_from_css_rule(rule, ns)
246
- visitor = Nokogiri::CSS::XPathVisitor.new(
247
- builtins: Nokogiri::CSS::XPathVisitor::BuiltinsConfig::OPTIMAL,
248
- doctype: document.xpath_doctype,
249
- )
250
237
  self.class::IMPLIED_XPATH_CONTEXTS.map do |implied_xpath_context|
251
- CSS.xpath_for(rule.to_s, {
238
+ visitor = Nokogiri::CSS::XPathVisitor.new(
239
+ builtins: Nokogiri::CSS::XPathVisitor::BuiltinsConfig::OPTIMAL,
240
+ doctype: document.xpath_doctype,
252
241
  prefix: implied_xpath_context,
253
- ns: ns,
254
- visitor: visitor,
255
- })
242
+ namespaces: ns,
243
+ )
244
+ CSS.xpath_for(rule.to_s, visitor: visitor)
256
245
  end.join(" | ")
257
246
  end
258
247
 
259
- def extract_params(params) # :nodoc:
260
- handler = params.find do |param|
261
- ![Hash, String, Symbol].include?(param.class)
248
+ def xpath_internal(node, paths, handler, ns, binds)
249
+ document = node.document
250
+ return NodeSet.new(document) unless document
251
+
252
+ if paths.length == 1
253
+ return xpath_impl(node, paths.first, handler, ns, binds)
262
254
  end
263
- params -= [handler] if handler
264
255
 
265
- hashes = []
266
- while Hash === params.last || params.last.nil?
267
- hashes << params.pop
268
- break if params.empty?
256
+ NodeSet.new(document) do |combined|
257
+ paths.each do |path|
258
+ xpath_impl(node, path, handler, ns, binds).each { |set| combined << set }
259
+ end
269
260
  end
270
- ns, binds = hashes.reverse
261
+ end
271
262
 
272
- ns ||= document.root&.namespaces || {}
263
+ def xpath_impl(node, path, handler, ns, binds)
264
+ context = XPathContext.new(node)
265
+ context.register_namespaces(ns)
266
+ context.register_variables(binds)
273
267
 
274
- [params, handler, ns, binds]
268
+ path = path.gsub("xmlns:", " :") unless Nokogiri.uses_libxml?
269
+
270
+ context.evaluate(path, handler)
275
271
  end
276
272
  end
277
273
  end
@@ -6,11 +6,33 @@ module Nokogiri
6
6
  # This class provides information about XML SyntaxErrors. These
7
7
  # exceptions are typically stored on Nokogiri::XML::Document#errors.
8
8
  class SyntaxError < ::Nokogiri::SyntaxError
9
+ class << self
10
+ def aggregate(errors)
11
+ return nil if errors.empty?
12
+ return errors.first if errors.length == 1
13
+
14
+ messages = ["Multiple errors encountered:"]
15
+ errors.each do |error|
16
+ messages << error.to_s
17
+ end
18
+ new(messages.join("\n"))
19
+ end
20
+ end
21
+
9
22
  attr_reader :domain
10
23
  attr_reader :code
11
24
  attr_reader :level
12
25
  attr_reader :file
13
26
  attr_reader :line
27
+
28
+ # The XPath path of the node that caused the error when validating a `Nokogiri::XML::Document`.
29
+ #
30
+ # This attribute will only be non-nil when the error is emitted by `Schema#validate` on
31
+ # Document objects. It will return `nil` for DOM parsing errors and for errors emitted during
32
+ # Schema validation of files.
33
+ #
34
+ # ⚠ `#path` is not supported on JRuby, where it will always return `nil`.
35
+ attr_reader :path
14
36
  attr_reader :str1
15
37
  attr_reader :str2
16
38
  attr_reader :str3
@@ -6,9 +6,20 @@ module Nokogiri
6
6
  ###
7
7
  # Register namespaces in +namespaces+
8
8
  def register_namespaces(namespaces)
9
- namespaces.each do |k, v|
10
- k = k.to_s.gsub(/.*:/, "") # strip off 'xmlns:' or 'xml:'
11
- register_ns(k, v)
9
+ namespaces.each do |key, value|
10
+ key = key.to_s.gsub(/.*:/, "") # strip off 'xmlns:' or 'xml:'
11
+
12
+ register_ns(key, value)
13
+ end
14
+ end
15
+
16
+ def register_variables(binds)
17
+ return if binds.nil?
18
+
19
+ binds.each do |key, value|
20
+ key = key.to_s
21
+
22
+ register_variable(key, value)
12
23
  end
13
24
  end
14
25
  end
data/lib/nokogiri/xml.rb CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  module Nokogiri
4
4
  class << self
5
- ###
6
- # Parse XML. Convenience method for Nokogiri::XML::Document.parse
7
- def XML(thing, url = nil, encoding = nil, options = XML::ParseOptions::DEFAULT_XML, &block)
8
- Nokogiri::XML::Document.parse(thing, url, encoding, options, &block)
5
+ # Convenience method for Nokogiri::XML::Document.parse
6
+ def XML(...)
7
+ Nokogiri::XML::Document.parse(...)
9
8
  end
10
9
  end
11
10
 
@@ -16,31 +15,21 @@ module Nokogiri
16
15
  XML_C14N_EXCLUSIVE_1_0 = 1
17
16
  # C14N 1.1 spec canonicalization
18
17
  XML_C14N_1_1 = 2
19
- class << self
20
- ###
21
- # Parse an XML document using the Nokogiri::XML::Reader API. See
22
- # Nokogiri::XML::Reader for mor information
23
- def Reader(string_or_io, url = nil, encoding = nil, options = ParseOptions::STRICT)
24
- options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
25
- yield options if block_given?
26
-
27
- if string_or_io.respond_to?(:read)
28
- return Reader.from_io(string_or_io, url, encoding, options.to_i)
29
- end
30
18
 
31
- Reader.from_memory(string_or_io, url, encoding, options.to_i)
19
+ class << self
20
+ # Convenience method for Nokogiri::XML::Reader.new
21
+ def Reader(...)
22
+ Reader.new(...)
32
23
  end
33
24
 
34
- ###
35
- # Parse XML. Convenience method for Nokogiri::XML::Document.parse
36
- def parse(thing, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML, &block)
37
- Document.parse(thing, url, encoding, options, &block)
25
+ # Convenience method for Nokogiri::XML::Document.parse
26
+ def parse(...)
27
+ Document.parse(...)
38
28
  end
39
29
 
40
- ####
41
- # Parse a fragment from +string+ in to a NodeSet.
42
- def fragment(string, options = ParseOptions::DEFAULT_XML, &block)
43
- XML::DocumentFragment.parse(string, options, &block)
30
+ # Convenience method for Nokogiri::XML::DocumentFragment.parse
31
+ def fragment(...)
32
+ XML::DocumentFragment.parse(...)
44
33
  end
45
34
  end
46
35
  end
data/lib/nokogiri/xslt.rb CHANGED
@@ -3,15 +3,9 @@
3
3
 
4
4
  module Nokogiri
5
5
  class << self
6
- ###
7
- # Create a Nokogiri::XSLT::Stylesheet with +stylesheet+.
8
- #
9
- # Example:
10
- #
11
- # xslt = Nokogiri::XSLT(File.read(ARGV[0]))
12
- #
13
- def XSLT(stylesheet, modules = {})
14
- XSLT.parse(stylesheet, modules)
6
+ # Convenience method for Nokogiri::XSLT.parse
7
+ def XSLT(...)
8
+ XSLT.parse(...)
15
9
  end
16
10
  end
17
11
 
@@ -7,10 +7,9 @@ module XSD
7
7
  ###
8
8
  # Nokogiri XML parser for soap4r.
9
9
  #
10
- # Nokogiri may be used as the XML parser in soap4r. Simply require
11
- # 'xsd/xmlparser/nokogiri' in your soap4r applications, and soap4r
12
- # will use Nokogiri as it's XML parser. No other changes should be
13
- # required to use Nokogiri as the XML parser.
10
+ # Nokogiri may be used as the XML parser in soap4r. Require 'xsd/xmlparser/nokogiri' in your
11
+ # soap4r applications, and soap4r will use Nokogiri as its XML parser. No other changes should
12
+ # be required to use Nokogiri as the XML parser.
14
13
  #
15
14
  # Example (using UW ITS Web Services):
16
15
  #