rexml 3.3.9 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/NEWS.md +156 -1
- data/lib/rexml/attribute.rb +7 -8
- data/lib/rexml/cdata.rb +1 -1
- data/lib/rexml/child.rb +2 -3
- data/lib/rexml/comment.rb +1 -1
- data/lib/rexml/doctype.rb +3 -8
- data/lib/rexml/document.rb +18 -4
- data/lib/rexml/element.rb +53 -59
- data/lib/rexml/encoding.rb +3 -6
- data/lib/rexml/functions.rb +3 -3
- data/lib/rexml/instruction.rb +1 -1
- data/lib/rexml/namespace.rb +4 -4
- data/lib/rexml/node.rb +2 -2
- data/lib/rexml/parsers/baseparser.rb +195 -113
- data/lib/rexml/parsers/pullparser.rb +4 -0
- data/lib/rexml/parsers/xpathparser.rb +4 -4
- data/lib/rexml/quickpath.rb +19 -18
- data/lib/rexml/rexml.rb +1 -1
- data/lib/rexml/security.rb +2 -2
- data/lib/rexml/source.rb +61 -7
- data/lib/rexml/text.rb +29 -57
- data/lib/rexml/validation/relaxng.rb +27 -26
- data/lib/rexml/validation/validation.rb +8 -8
- data/lib/rexml/xpath.rb +2 -13
- data/lib/rexml/xpath_parser.rb +44 -42
- metadata +4 -4
data/lib/rexml/namespace.rb
CHANGED
@@ -42,11 +42,11 @@ module REXML
|
|
42
42
|
# Compares names optionally WITH namespaces
|
43
43
|
def has_name?( other, ns=nil )
|
44
44
|
if ns
|
45
|
-
|
45
|
+
namespace() == ns and name() == other
|
46
46
|
elsif other.include? ":"
|
47
|
-
|
47
|
+
fully_expanded_name == other
|
48
48
|
else
|
49
|
-
|
49
|
+
name == other
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -57,7 +57,7 @@ module REXML
|
|
57
57
|
def fully_expanded_name
|
58
58
|
ns = prefix
|
59
59
|
return "#{ns}:#@name" if ns.size > 0
|
60
|
-
|
60
|
+
@name
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
data/lib/rexml/node.rb
CHANGED
@@ -26,7 +26,7 @@ module REXML
|
|
26
26
|
# REXML::Formatters package for changing the output style.
|
27
27
|
def to_s indent=nil
|
28
28
|
unless indent.nil?
|
29
|
-
Kernel.warn( "#{self.class.name}
|
29
|
+
Kernel.warn( "#{self.class.name}#to_s(indent) parameter is deprecated", uplevel: 1)
|
30
30
|
f = REXML::Formatters::Pretty.new( indent )
|
31
31
|
f.write( self, rv = "" )
|
32
32
|
else
|
@@ -68,7 +68,7 @@ module REXML
|
|
68
68
|
each_recursive {|node|
|
69
69
|
return node if block.call(node)
|
70
70
|
}
|
71
|
-
|
71
|
+
nil
|
72
72
|
end
|
73
73
|
|
74
74
|
# Returns the position that +self+ holds in its parent's array, indexed
|
@@ -144,6 +144,7 @@ module REXML
|
|
144
144
|
PEREFERENCE_PATTERN = /#{PEREFERENCE}/um
|
145
145
|
TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
|
146
146
|
CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
|
147
|
+
EQUAL_PATTERN = /\s*=\s*/um
|
147
148
|
ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
|
148
149
|
NAME_PATTERN = /#{NAME}/um
|
149
150
|
GEDECL_PATTERN = "\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
|
@@ -168,6 +169,7 @@ module REXML
|
|
168
169
|
@entity_expansion_limit = Security.entity_expansion_limit
|
169
170
|
@entity_expansion_text_limit = Security.entity_expansion_text_limit
|
170
171
|
@source.ensure_buffer
|
172
|
+
@version = nil
|
171
173
|
end
|
172
174
|
|
173
175
|
def add_listener( listener )
|
@@ -181,6 +183,10 @@ module REXML
|
|
181
183
|
|
182
184
|
def stream=( source )
|
183
185
|
@source = SourceFactory.create_from( source )
|
186
|
+
reset
|
187
|
+
end
|
188
|
+
|
189
|
+
def reset
|
184
190
|
@closed = nil
|
185
191
|
@have_root = false
|
186
192
|
@document_status = nil
|
@@ -202,12 +208,12 @@ module REXML
|
|
202
208
|
|
203
209
|
# Returns true if there are no more events
|
204
210
|
def empty?
|
205
|
-
|
211
|
+
(@source.empty? and @stack.empty?)
|
206
212
|
end
|
207
213
|
|
208
214
|
# Returns true if there are more events. Synonymous with !empty?
|
209
215
|
def has_next?
|
210
|
-
|
216
|
+
!(@source.empty? and @stack.empty?)
|
211
217
|
end
|
212
218
|
|
213
219
|
# Push an event back on the head of the stream. This method
|
@@ -269,22 +275,15 @@ module REXML
|
|
269
275
|
@source.ensure_buffer
|
270
276
|
if @document_status == nil
|
271
277
|
start_position = @source.position
|
272
|
-
if @source.match("<?", true)
|
278
|
+
if @source.match?("<?", true)
|
273
279
|
return process_instruction
|
274
|
-
elsif @source.match("<!", true)
|
275
|
-
if @source.match("--", true)
|
276
|
-
|
277
|
-
|
278
|
-
raise REXML::ParseException.new("Unclosed comment", @source)
|
279
|
-
end
|
280
|
-
if /--|-\z/.match?(md[1])
|
281
|
-
raise REXML::ParseException.new("Malformed comment", @source)
|
282
|
-
end
|
283
|
-
return [ :comment, md[1] ]
|
284
|
-
elsif @source.match("DOCTYPE", true)
|
280
|
+
elsif @source.match?("<!", true)
|
281
|
+
if @source.match?("--", true)
|
282
|
+
return [ :comment, process_comment ]
|
283
|
+
elsif @source.match?("DOCTYPE", true)
|
285
284
|
base_error_message = "Malformed DOCTYPE"
|
286
|
-
unless @source.
|
287
|
-
if @source.match(">")
|
285
|
+
unless @source.skip_spaces
|
286
|
+
if @source.match?(">")
|
288
287
|
message = "#{base_error_message}: name is missing"
|
289
288
|
else
|
290
289
|
message = "#{base_error_message}: invalid name"
|
@@ -293,10 +292,11 @@ module REXML
|
|
293
292
|
raise REXML::ParseException.new(message, @source)
|
294
293
|
end
|
295
294
|
name = parse_name(base_error_message)
|
296
|
-
|
295
|
+
@source.skip_spaces
|
296
|
+
if @source.match?("[", true)
|
297
297
|
id = [nil, nil, nil]
|
298
298
|
@document_status = :in_doctype
|
299
|
-
elsif @source.match(
|
299
|
+
elsif @source.match?(">", true)
|
300
300
|
id = [nil, nil, nil]
|
301
301
|
@document_status = :after_doctype
|
302
302
|
@source.ensure_buffer
|
@@ -308,9 +308,10 @@ module REXML
|
|
308
308
|
# For backward compatibility
|
309
309
|
id[1], id[2] = id[2], nil
|
310
310
|
end
|
311
|
-
|
311
|
+
@source.skip_spaces
|
312
|
+
if @source.match?("[", true)
|
312
313
|
@document_status = :in_doctype
|
313
|
-
elsif @source.match(
|
314
|
+
elsif @source.match?(">", true)
|
314
315
|
@document_status = :after_doctype
|
315
316
|
@source.ensure_buffer
|
316
317
|
else
|
@@ -320,7 +321,7 @@ module REXML
|
|
320
321
|
end
|
321
322
|
args = [:start_doctype, name, *id]
|
322
323
|
if @document_status == :after_doctype
|
323
|
-
@source.
|
324
|
+
@source.skip_spaces
|
324
325
|
@stack << [ :end_doctype ]
|
325
326
|
end
|
326
327
|
return args
|
@@ -331,14 +332,14 @@ module REXML
|
|
331
332
|
end
|
332
333
|
end
|
333
334
|
if @document_status == :in_doctype
|
334
|
-
@source.
|
335
|
+
@source.skip_spaces
|
335
336
|
start_position = @source.position
|
336
|
-
if @source.match("<!", true)
|
337
|
-
if @source.match("ELEMENT", true)
|
337
|
+
if @source.match?("<!", true)
|
338
|
+
if @source.match?("ELEMENT", true)
|
338
339
|
md = @source.match(/(.*?)>/um, true)
|
339
340
|
raise REXML::ParseException.new( "Bad ELEMENT declaration!", @source ) if md.nil?
|
340
341
|
return [ :elementdecl, "<!ELEMENT" + md[1] ]
|
341
|
-
elsif @source.match("ENTITY", true)
|
342
|
+
elsif @source.match?("ENTITY", true)
|
342
343
|
match_data = @source.match(Private::ENTITYDECL_PATTERN, true)
|
343
344
|
unless match_data
|
344
345
|
raise REXML::ParseException.new("Malformed entity declaration", @source)
|
@@ -370,11 +371,11 @@ module REXML
|
|
370
371
|
end
|
371
372
|
match << '%' if ref
|
372
373
|
return match
|
373
|
-
elsif @source.match("ATTLIST", true)
|
374
|
+
elsif @source.match?("ATTLIST", true)
|
374
375
|
md = @source.match(Private::ATTLISTDECL_END, true)
|
375
376
|
raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
|
376
377
|
element = md[1]
|
377
|
-
contents = md[0]
|
378
|
+
contents = "<!ATTLIST" + md[0]
|
378
379
|
|
379
380
|
pairs = {}
|
380
381
|
values = md[0].strip.scan( ATTDEF_RE )
|
@@ -390,10 +391,10 @@ module REXML
|
|
390
391
|
end
|
391
392
|
end
|
392
393
|
return [ :attlistdecl, element, pairs, contents ]
|
393
|
-
elsif @source.match("NOTATION", true)
|
394
|
+
elsif @source.match?("NOTATION", true)
|
394
395
|
base_error_message = "Malformed notation declaration"
|
395
|
-
unless @source.
|
396
|
-
if @source.match(">")
|
396
|
+
unless @source.skip_spaces
|
397
|
+
if @source.match?(">")
|
397
398
|
message = "#{base_error_message}: name is missing"
|
398
399
|
else
|
399
400
|
message = "#{base_error_message}: invalid name"
|
@@ -405,39 +406,37 @@ module REXML
|
|
405
406
|
id = parse_id(base_error_message,
|
406
407
|
accept_external_id: true,
|
407
408
|
accept_public_id: true)
|
408
|
-
|
409
|
+
@source.skip_spaces
|
410
|
+
unless @source.match?(">", true)
|
409
411
|
message = "#{base_error_message}: garbage before end >"
|
410
412
|
raise REXML::ParseException.new(message, @source)
|
411
413
|
end
|
412
414
|
return [:notationdecl, name, *id]
|
413
|
-
elsif
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
end
|
418
|
-
return [ :comment, md[1] ] if md
|
415
|
+
elsif @source.match?("--", true)
|
416
|
+
return [ :comment, process_comment ]
|
417
|
+
else
|
418
|
+
raise REXML::ParseException.new("Malformed node: Started with '<!' but not a comment nor ELEMENT,ENTITY,ATTLIST,NOTATION", @source)
|
419
419
|
end
|
420
420
|
elsif match = @source.match(/(%.*?;)\s*/um, true)
|
421
421
|
return [ :externalentity, match[1] ]
|
422
|
-
elsif @source.match(/\]\s*>/um, true)
|
422
|
+
elsif @source.match?(/\]\s*>/um, true)
|
423
423
|
@document_status = :after_doctype
|
424
424
|
return [ :end_doctype ]
|
425
|
-
|
426
|
-
if @document_status == :in_doctype
|
425
|
+
else
|
427
426
|
raise ParseException.new("Malformed DOCTYPE: invalid declaration", @source)
|
428
427
|
end
|
429
428
|
end
|
430
429
|
if @document_status == :after_doctype
|
431
|
-
@source.
|
430
|
+
@source.skip_spaces
|
432
431
|
end
|
433
432
|
begin
|
434
433
|
start_position = @source.position
|
435
|
-
if @source.match("<", true)
|
434
|
+
if @source.match?("<", true)
|
436
435
|
# :text's read_until may remain only "<" in buffer. In the
|
437
436
|
# case, buffer is empty here. So we need to fill buffer
|
438
437
|
# here explicitly.
|
439
438
|
@source.ensure_buffer
|
440
|
-
if @source.match("/", true)
|
439
|
+
if @source.match?("/", true)
|
441
440
|
@namespaces_restore_stack.pop
|
442
441
|
last_tag = @tags.pop
|
443
442
|
md = @source.match(Private::CLOSE_PATTERN, true)
|
@@ -452,25 +451,21 @@ module REXML
|
|
452
451
|
raise REXML::ParseException.new(message, @source)
|
453
452
|
end
|
454
453
|
return [ :end_element, last_tag ]
|
455
|
-
elsif @source.match("!", true)
|
456
|
-
md = @source.match(/([^>]*>)/um)
|
454
|
+
elsif @source.match?("!", true)
|
457
455
|
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
if
|
463
|
-
|
456
|
+
if @source.match?("--", true)
|
457
|
+
return [ :comment, process_comment ]
|
458
|
+
elsif @source.match?("[CDATA[", true)
|
459
|
+
text = @source.read_until("]]>")
|
460
|
+
if text.chomp!("]]>")
|
461
|
+
return [ :cdata, text ]
|
462
|
+
else
|
463
|
+
raise REXML::ParseException.new("Malformed CDATA: Missing end ']]>'", @source)
|
464
464
|
end
|
465
|
-
|
466
|
-
return [ :comment, md[1] ]
|
467
465
|
else
|
468
|
-
|
469
|
-
return [ :cdata, md[1] ] if md
|
466
|
+
raise REXML::ParseException.new("Malformed node: Started with '<!' but not a comment nor CDATA", @source)
|
470
467
|
end
|
471
|
-
|
472
|
-
"in the doctype declaration.", @source)
|
473
|
-
elsif @source.match("?", true)
|
468
|
+
elsif @source.match?("?", true)
|
474
469
|
return process_instruction
|
475
470
|
else
|
476
471
|
# Get the next tag
|
@@ -529,7 +524,8 @@ module REXML
|
|
529
524
|
raise REXML::ParseException.new( "Exception parsing",
|
530
525
|
@source, self, (error ? error : $!) )
|
531
526
|
end
|
532
|
-
|
527
|
+
# NOTE: The end of the method never runs, because it is unreachable.
|
528
|
+
# All branches of code above have explicit unconditional return or raise statements.
|
533
529
|
end
|
534
530
|
private :pull_event
|
535
531
|
|
@@ -648,10 +644,14 @@ module REXML
|
|
648
644
|
true
|
649
645
|
end
|
650
646
|
|
647
|
+
def normalize_xml_declaration_encoding(xml_declaration_encoding)
|
648
|
+
/\AUTF-16(?:BE|LE)\z/i.match?(xml_declaration_encoding) ? "UTF-16" : nil
|
649
|
+
end
|
650
|
+
|
651
651
|
def parse_name(base_error_message)
|
652
652
|
md = @source.match(Private::NAME_PATTERN, true)
|
653
653
|
unless md
|
654
|
-
if @source.match(/\S/um)
|
654
|
+
if @source.match?(/\S/um)
|
655
655
|
message = "#{base_error_message}: invalid name"
|
656
656
|
else
|
657
657
|
message = "#{base_error_message}: name is missing"
|
@@ -693,73 +693,171 @@ module REXML
|
|
693
693
|
accept_public_id:)
|
694
694
|
public = /\A\s*PUBLIC/um
|
695
695
|
system = /\A\s*SYSTEM/um
|
696
|
-
if (accept_external_id or accept_public_id) and @source.match(/#{public}/um)
|
697
|
-
if @source.match(/#{public}(?:\s+[^'"]|\s*[\[>])/um)
|
696
|
+
if (accept_external_id or accept_public_id) and @source.match?(/#{public}/um)
|
697
|
+
if @source.match?(/#{public}(?:\s+[^'"]|\s*[\[>])/um)
|
698
698
|
return "public ID literal is missing"
|
699
699
|
end
|
700
|
-
unless @source.match(/#{public}\s+#{PUBIDLITERAL}/um)
|
700
|
+
unless @source.match?(/#{public}\s+#{PUBIDLITERAL}/um)
|
701
701
|
return "invalid public ID literal"
|
702
702
|
end
|
703
703
|
if accept_public_id
|
704
|
-
if @source.match(/#{public}\s+#{PUBIDLITERAL}\s+[^'"]/um)
|
704
|
+
if @source.match?(/#{public}\s+#{PUBIDLITERAL}\s+[^'"]/um)
|
705
705
|
return "system ID literal is missing"
|
706
706
|
end
|
707
|
-
unless @source.match(/#{public}\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}/um)
|
707
|
+
unless @source.match?(/#{public}\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}/um)
|
708
708
|
return "invalid system literal"
|
709
709
|
end
|
710
710
|
"garbage after system literal"
|
711
711
|
else
|
712
712
|
"garbage after public ID literal"
|
713
713
|
end
|
714
|
-
elsif accept_external_id and @source.match(/#{system}/um)
|
715
|
-
if @source.match(/#{system}(?:\s+[^'"]|\s*[\[>])/um)
|
714
|
+
elsif accept_external_id and @source.match?(/#{system}/um)
|
715
|
+
if @source.match?(/#{system}(?:\s+[^'"]|\s*[\[>])/um)
|
716
716
|
return "system literal is missing"
|
717
717
|
end
|
718
|
-
unless @source.match(/#{system}\s+#{SYSTEMLITERAL}/um)
|
718
|
+
unless @source.match?(/#{system}\s+#{SYSTEMLITERAL}/um)
|
719
719
|
return "invalid system literal"
|
720
720
|
end
|
721
721
|
"garbage after system literal"
|
722
722
|
else
|
723
|
-
unless @source.match(/\A\s*(?:PUBLIC|SYSTEM)\s/um)
|
723
|
+
unless @source.match?(/\A\s*(?:PUBLIC|SYSTEM)\s/um)
|
724
724
|
return "invalid ID type"
|
725
725
|
end
|
726
726
|
"ID type is missing"
|
727
727
|
end
|
728
728
|
end
|
729
729
|
|
730
|
+
def process_comment
|
731
|
+
text = @source.read_until("-->")
|
732
|
+
unless text.chomp!("-->")
|
733
|
+
raise REXML::ParseException.new("Unclosed comment: Missing end '-->'", @source)
|
734
|
+
end
|
735
|
+
|
736
|
+
if text.include? "--" or text.end_with?("-")
|
737
|
+
raise REXML::ParseException.new("Malformed comment", @source)
|
738
|
+
end
|
739
|
+
text
|
740
|
+
end
|
741
|
+
|
730
742
|
def process_instruction
|
731
743
|
name = parse_name("Malformed XML: Invalid processing instruction node")
|
732
|
-
if
|
733
|
-
|
734
|
-
|
735
|
-
|
744
|
+
if name == "xml"
|
745
|
+
xml_declaration
|
746
|
+
else # PITarget
|
747
|
+
if @source.skip_spaces # e.g. <?name content?>
|
748
|
+
start_position = @source.position
|
749
|
+
content = @source.read_until("?>")
|
750
|
+
unless content.chomp!("?>")
|
751
|
+
@source.position = start_position
|
752
|
+
raise ParseException.new("Malformed XML: Unclosed processing instruction: <#{name}>", @source)
|
753
|
+
end
|
754
|
+
else # e.g. <?name?>
|
755
|
+
content = nil
|
756
|
+
unless @source.match?("?>", true)
|
757
|
+
raise ParseException.new("Malformed XML: Unclosed processing instruction: <#{name}>", @source)
|
758
|
+
end
|
736
759
|
end
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
760
|
+
[:processing_instruction, name, content]
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
def xml_declaration
|
765
|
+
unless @version.nil?
|
766
|
+
raise ParseException.new("Malformed XML: XML declaration is duplicated", @source)
|
767
|
+
end
|
768
|
+
if @document_status
|
769
|
+
raise ParseException.new("Malformed XML: XML declaration is not at the start", @source)
|
770
|
+
end
|
771
|
+
unless @source.skip_spaces
|
772
|
+
raise ParseException.new("Malformed XML: XML declaration misses spaces before version", @source)
|
773
|
+
end
|
774
|
+
unless @source.match?("version", true)
|
775
|
+
raise ParseException.new("Malformed XML: XML declaration misses version", @source)
|
776
|
+
end
|
777
|
+
@version = parse_attribute_value_with_equal("xml")
|
778
|
+
unless @source.skip_spaces
|
779
|
+
unless @source.match?("?>", true)
|
780
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
742
781
|
end
|
782
|
+
encoding = normalize_xml_declaration_encoding(@source.encoding)
|
783
|
+
return [ :xmldecl, @version, encoding, nil ] # e.g. <?xml version="1.0"?>
|
743
784
|
end
|
744
|
-
|
745
|
-
|
746
|
-
|
785
|
+
|
786
|
+
if @source.match?("encoding", true)
|
787
|
+
encoding = parse_attribute_value_with_equal("xml")
|
788
|
+
unless @source.skip_spaces
|
789
|
+
unless @source.match?("?>", true)
|
790
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
791
|
+
end
|
792
|
+
if need_source_encoding_update?(encoding)
|
793
|
+
@source.encoding = encoding
|
794
|
+
end
|
795
|
+
encoding ||= normalize_xml_declaration_encoding(@source.encoding)
|
796
|
+
return [ :xmldecl, @version, encoding, nil ] # e.g. <?xml version="1.1" encoding="UTF-8"?>
|
747
797
|
end
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
798
|
+
end
|
799
|
+
|
800
|
+
if @source.match?("standalone", true)
|
801
|
+
standalone = parse_attribute_value_with_equal("xml")
|
802
|
+
case standalone
|
803
|
+
when "yes", "no"
|
804
|
+
else
|
805
|
+
raise ParseException.new("Malformed XML: XML declaration standalone is not yes or no : <#{standalone}>", @source)
|
754
806
|
end
|
755
|
-
|
756
|
-
|
807
|
+
end
|
808
|
+
@source.skip_spaces
|
809
|
+
unless @source.match?("?>", true)
|
810
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
811
|
+
end
|
812
|
+
|
813
|
+
if need_source_encoding_update?(encoding)
|
814
|
+
@source.encoding = encoding
|
815
|
+
end
|
816
|
+
encoding ||= normalize_xml_declaration_encoding(@source.encoding)
|
817
|
+
|
818
|
+
# e.g. <?xml version="1.0" ?>
|
819
|
+
# <?xml version="1.1" encoding="UTF-8" ?>
|
820
|
+
# <?xml version="1.1" standalone="yes"?>
|
821
|
+
# <?xml version="1.1" encoding="UTF-8" standalone="yes" ?>
|
822
|
+
[ :xmldecl, @version, encoding, standalone ]
|
823
|
+
end
|
824
|
+
|
825
|
+
if StringScanner::Version < "3.1.1"
|
826
|
+
def scan_quote
|
827
|
+
@source.match(/(['"])/, true)&.[](1)
|
828
|
+
end
|
829
|
+
else
|
830
|
+
def scan_quote
|
831
|
+
case @source.peek_byte
|
832
|
+
when 34 # '"'.ord
|
833
|
+
@source.scan_byte
|
834
|
+
'"'
|
835
|
+
when 39 # "'".ord
|
836
|
+
@source.scan_byte
|
837
|
+
"'"
|
838
|
+
else
|
839
|
+
nil
|
757
840
|
end
|
758
|
-
standalone = STANDALONE.match(content)
|
759
|
-
standalone = standalone[1] unless standalone.nil?
|
760
|
-
return [ :xmldecl, version, encoding, standalone ]
|
761
841
|
end
|
762
|
-
|
842
|
+
end
|
843
|
+
|
844
|
+
def parse_attribute_value_with_equal(name)
|
845
|
+
unless @source.match?(Private::EQUAL_PATTERN, true)
|
846
|
+
message = "Missing attribute equal: <#{name}>"
|
847
|
+
raise REXML::ParseException.new(message, @source)
|
848
|
+
end
|
849
|
+
unless quote = scan_quote
|
850
|
+
message = "Missing attribute value start quote: <#{name}>"
|
851
|
+
raise REXML::ParseException.new(message, @source)
|
852
|
+
end
|
853
|
+
start_position = @source.position
|
854
|
+
value = @source.read_until(quote)
|
855
|
+
unless value.chomp!(quote)
|
856
|
+
@source.position = start_position
|
857
|
+
message = "Missing attribute value end quote: <#{name}>: <#{quote}>"
|
858
|
+
raise REXML::ParseException.new(message, @source)
|
859
|
+
end
|
860
|
+
value
|
763
861
|
end
|
764
862
|
|
765
863
|
def parse_attributes(prefixes)
|
@@ -767,33 +865,17 @@ module REXML
|
|
767
865
|
expanded_names = {}
|
768
866
|
closed = false
|
769
867
|
while true
|
770
|
-
if @source.match(">", true)
|
868
|
+
if @source.match?(">", true)
|
771
869
|
return attributes, closed
|
772
|
-
elsif @source.match("/>", true)
|
870
|
+
elsif @source.match?("/>", true)
|
773
871
|
closed = true
|
774
872
|
return attributes, closed
|
775
873
|
elsif match = @source.match(QNAME, true)
|
776
874
|
name = match[1]
|
777
875
|
prefix = match[2]
|
778
876
|
local_part = match[3]
|
779
|
-
|
780
|
-
|
781
|
-
message = "Missing attribute equal: <#{name}>"
|
782
|
-
raise REXML::ParseException.new(message, @source)
|
783
|
-
end
|
784
|
-
unless match = @source.match(/(['"])/, true)
|
785
|
-
message = "Missing attribute value start quote: <#{name}>"
|
786
|
-
raise REXML::ParseException.new(message, @source)
|
787
|
-
end
|
788
|
-
quote = match[1]
|
789
|
-
start_position = @source.position
|
790
|
-
value = @source.read_until(quote)
|
791
|
-
unless value.chomp!(quote)
|
792
|
-
@source.position = start_position
|
793
|
-
message = "Missing attribute value end quote: <#{name}>: <#{quote}>"
|
794
|
-
raise REXML::ParseException.new(message, @source)
|
795
|
-
end
|
796
|
-
@source.match(/\s*/um, true)
|
877
|
+
value = parse_attribute_value_with_equal(name)
|
878
|
+
@source.skip_spaces
|
797
879
|
if prefix == "xmlns"
|
798
880
|
if local_part == "xml"
|
799
881
|
if value != Private::XML_PREFIXED_NAMESPACE
|
@@ -215,7 +215,7 @@ module REXML
|
|
215
215
|
else
|
216
216
|
path << yield( parsed )
|
217
217
|
end
|
218
|
-
|
218
|
+
path.squeeze(" ")
|
219
219
|
end
|
220
220
|
# For backward compatibility
|
221
221
|
alias_method :preciate_to_string, :predicate_to_path
|
@@ -252,7 +252,7 @@ module REXML
|
|
252
252
|
path = path[1..-1]
|
253
253
|
end
|
254
254
|
end
|
255
|
-
|
255
|
+
RelativeLocationPath( path, parsed ) if path.size > 0
|
256
256
|
end
|
257
257
|
|
258
258
|
#RelativeLocationPath
|
@@ -388,7 +388,7 @@ module REXML
|
|
388
388
|
else
|
389
389
|
path = original_path
|
390
390
|
end
|
391
|
-
|
391
|
+
path
|
392
392
|
end
|
393
393
|
|
394
394
|
# Filters the supplied nodeset on the predicate(s)
|
@@ -600,7 +600,7 @@ module REXML
|
|
600
600
|
end
|
601
601
|
rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
|
602
602
|
parsed.concat(n)
|
603
|
-
|
603
|
+
rest
|
604
604
|
end
|
605
605
|
|
606
606
|
#| FilterExpr Predicate
|