rexml 3.2.5 → 3.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +406 -2
- data/README.md +10 -1
- data/doc/rexml/tasks/rdoc/element.rdoc +2 -2
- data/doc/rexml/tutorial.rdoc +1358 -0
- data/lib/rexml/attribute.rb +14 -9
- data/lib/rexml/document.rb +1 -1
- data/lib/rexml/element.rb +19 -34
- data/lib/rexml/entity.rb +5 -37
- data/lib/rexml/formatters/pretty.rb +3 -3
- data/lib/rexml/functions.rb +1 -2
- data/lib/rexml/namespace.rb +8 -4
- data/lib/rexml/node.rb +8 -4
- data/lib/rexml/parseexception.rb +1 -0
- data/lib/rexml/parsers/baseparser.rb +421 -263
- data/lib/rexml/parsers/pullparser.rb +4 -0
- data/lib/rexml/parsers/sax2parser.rb +6 -19
- data/lib/rexml/parsers/streamparser.rb +8 -10
- data/lib/rexml/parsers/treeparser.rb +9 -21
- data/lib/rexml/parsers/xpathparser.rb +136 -86
- data/lib/rexml/rexml.rb +3 -1
- data/lib/rexml/source.rb +128 -98
- data/lib/rexml/text.rb +40 -18
- data/lib/rexml/xpath_parser.rb +7 -3
- metadata +11 -39
@@ -22,6 +22,10 @@ module REXML
|
|
22
22
|
@parser.source
|
23
23
|
end
|
24
24
|
|
25
|
+
def entity_expansion_count
|
26
|
+
@parser.entity_expansion_count
|
27
|
+
end
|
28
|
+
|
25
29
|
def add_listener( listener )
|
26
30
|
@parser.add_listener( listener )
|
27
31
|
end
|
@@ -157,25 +161,8 @@ module REXML
|
|
157
161
|
end
|
158
162
|
end
|
159
163
|
when :text
|
160
|
-
|
161
|
-
|
162
|
-
copy = event[1].clone
|
163
|
-
|
164
|
-
esub = proc { |match|
|
165
|
-
if @entities.has_key?($1)
|
166
|
-
@entities[$1].gsub(Text::REFERENCE, &esub)
|
167
|
-
else
|
168
|
-
match
|
169
|
-
end
|
170
|
-
}
|
171
|
-
|
172
|
-
copy.gsub!( Text::REFERENCE, &esub )
|
173
|
-
copy.gsub!( Text::NUMERICENTITY ) {|m|
|
174
|
-
m=$1
|
175
|
-
m = "0#{m}" if m[0] == ?x
|
176
|
-
[Integer(m)].pack('U*')
|
177
|
-
}
|
178
|
-
handle( :characters, copy )
|
164
|
+
unnormalized = @parser.unnormalize( event[1], @entities )
|
165
|
+
handle( :characters, unnormalized )
|
179
166
|
when :entitydecl
|
180
167
|
handle_entitydecl( event )
|
181
168
|
when :processing_instruction, :comment, :attlistdecl,
|
@@ -7,37 +7,34 @@ module REXML
|
|
7
7
|
def initialize source, listener
|
8
8
|
@listener = listener
|
9
9
|
@parser = BaseParser.new( source )
|
10
|
-
@
|
10
|
+
@entities = {}
|
11
11
|
end
|
12
12
|
|
13
13
|
def add_listener( listener )
|
14
14
|
@parser.add_listener( listener )
|
15
15
|
end
|
16
16
|
|
17
|
+
def entity_expansion_count
|
18
|
+
@parser.entity_expansion_count
|
19
|
+
end
|
20
|
+
|
17
21
|
def parse
|
18
22
|
# entity string
|
19
23
|
while true
|
20
24
|
event = @parser.pull
|
21
25
|
case event[0]
|
22
26
|
when :end_document
|
23
|
-
unless @tag_stack.empty?
|
24
|
-
tag_path = "/" + @tag_stack.join("/")
|
25
|
-
raise ParseException.new("Missing end tag for '#{tag_path}'",
|
26
|
-
@parser.source)
|
27
|
-
end
|
28
27
|
return
|
29
28
|
when :start_element
|
30
|
-
@tag_stack << event[1]
|
31
29
|
attrs = event[2].each do |n, v|
|
32
30
|
event[2][n] = @parser.unnormalize( v )
|
33
31
|
end
|
34
32
|
@listener.tag_start( event[1], attrs )
|
35
33
|
when :end_element
|
36
34
|
@listener.tag_end( event[1] )
|
37
|
-
@tag_stack.pop
|
38
35
|
when :text
|
39
|
-
|
40
|
-
@listener.text(
|
36
|
+
unnormalized = @parser.unnormalize( event[1], @entities )
|
37
|
+
@listener.text( unnormalized )
|
41
38
|
when :processing_instruction
|
42
39
|
@listener.instruction( *event[1,2] )
|
43
40
|
when :start_doctype
|
@@ -48,6 +45,7 @@ module REXML
|
|
48
45
|
when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
|
49
46
|
@listener.send( event[0].to_s, *event[1..-1] )
|
50
47
|
when :entitydecl, :notationdecl
|
48
|
+
@entities[ event[1] ] = event[2] if event.size == 3
|
51
49
|
@listener.send( event[0].to_s, event[1..-1] )
|
52
50
|
when :externalentity
|
53
51
|
entity_reference = event[1]
|
@@ -15,8 +15,6 @@ module REXML
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def parse
|
18
|
-
tag_stack = []
|
19
|
-
in_doctype = false
|
20
18
|
entities = nil
|
21
19
|
begin
|
22
20
|
while true
|
@@ -24,32 +22,24 @@ module REXML
|
|
24
22
|
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
|
25
23
|
case event[0]
|
26
24
|
when :end_document
|
27
|
-
unless tag_stack.empty?
|
28
|
-
raise ParseException.new("No close tag for #{@build_context.xpath}",
|
29
|
-
@parser.source, @parser)
|
30
|
-
end
|
31
25
|
return
|
32
26
|
when :start_element
|
33
|
-
tag_stack.push(event[1])
|
34
27
|
el = @build_context = @build_context.add_element( event[1] )
|
35
28
|
event[2].each do |key, value|
|
36
29
|
el.attributes[key]=Attribute.new(key,value,self)
|
37
30
|
end
|
38
31
|
when :end_element
|
39
|
-
tag_stack.pop
|
40
32
|
@build_context = @build_context.parent
|
41
33
|
when :text
|
42
|
-
if
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@build_context.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
)
|
52
|
-
end
|
34
|
+
if @build_context[-1].instance_of? Text
|
35
|
+
@build_context[-1] << event[1]
|
36
|
+
else
|
37
|
+
@build_context.add(
|
38
|
+
Text.new(event[1], @build_context.whitespace, nil, true)
|
39
|
+
) unless (
|
40
|
+
@build_context.ignore_whitespace_nodes and
|
41
|
+
event[1].strip.size==0
|
42
|
+
)
|
53
43
|
end
|
54
44
|
when :comment
|
55
45
|
c = Comment.new( event[1] )
|
@@ -60,14 +50,12 @@ module REXML
|
|
60
50
|
when :processing_instruction
|
61
51
|
@build_context.add( Instruction.new( event[1], event[2] ) )
|
62
52
|
when :end_doctype
|
63
|
-
in_doctype = false
|
64
53
|
entities.each { |k,v| entities[k] = @build_context.entities[k].value }
|
65
54
|
@build_context = @build_context.parent
|
66
55
|
when :start_doctype
|
67
56
|
doctype = DocType.new( event[1..-1], @build_context )
|
68
57
|
@build_context = doctype
|
69
58
|
entities = {}
|
70
|
-
in_doctype = true
|
71
59
|
when :attlistdecl
|
72
60
|
n = AttlistDecl.new( event[1..-1] )
|
73
61
|
@build_context.add( n )
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
|
+
|
2
3
|
require_relative '../namespace'
|
3
4
|
require_relative '../xmltokens'
|
4
5
|
|
@@ -38,108 +39,143 @@ module REXML
|
|
38
39
|
parsed
|
39
40
|
end
|
40
41
|
|
41
|
-
def abbreviate(
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
def abbreviate(path_or_parsed)
|
43
|
+
if path_or_parsed.kind_of?(String)
|
44
|
+
parsed = parse(path_or_parsed)
|
45
|
+
else
|
46
|
+
parsed = path_or_parsed
|
47
|
+
end
|
48
|
+
components = []
|
49
|
+
component = nil
|
50
|
+
while parsed.size > 0
|
51
|
+
op = parsed.shift
|
47
52
|
case op
|
48
53
|
when :node
|
54
|
+
component << "node()"
|
49
55
|
when :attribute
|
50
|
-
|
51
|
-
|
56
|
+
component = "@"
|
57
|
+
components << component
|
52
58
|
when :child
|
53
|
-
|
59
|
+
component = ""
|
60
|
+
components << component
|
54
61
|
when :descendant_or_self
|
55
|
-
|
62
|
+
next_op = parsed[0]
|
63
|
+
if next_op == :node
|
64
|
+
parsed.shift
|
65
|
+
component = ""
|
66
|
+
components << component
|
67
|
+
else
|
68
|
+
component = "descendant-or-self::"
|
69
|
+
components << component
|
70
|
+
end
|
56
71
|
when :self
|
57
|
-
|
72
|
+
next_op = parsed[0]
|
73
|
+
if next_op == :node
|
74
|
+
parsed.shift
|
75
|
+
components << "."
|
76
|
+
else
|
77
|
+
component = "self::"
|
78
|
+
components << component
|
79
|
+
end
|
58
80
|
when :parent
|
59
|
-
|
81
|
+
next_op = parsed[0]
|
82
|
+
if next_op == :node
|
83
|
+
parsed.shift
|
84
|
+
components << ".."
|
85
|
+
else
|
86
|
+
component = "parent::"
|
87
|
+
components << component
|
88
|
+
end
|
60
89
|
when :any
|
61
|
-
|
90
|
+
component << "*"
|
62
91
|
when :text
|
63
|
-
|
92
|
+
component << "text()"
|
64
93
|
when :following, :following_sibling,
|
65
94
|
:ancestor, :ancestor_or_self, :descendant,
|
66
95
|
:namespace, :preceding, :preceding_sibling
|
67
|
-
|
68
|
-
|
69
|
-
string << "::"
|
96
|
+
component = op.to_s.tr("_", "-") << "::"
|
97
|
+
components << component
|
70
98
|
when :qname
|
71
|
-
prefix =
|
72
|
-
name =
|
73
|
-
|
74
|
-
|
99
|
+
prefix = parsed.shift
|
100
|
+
name = parsed.shift
|
101
|
+
component << prefix+":" if prefix.size > 0
|
102
|
+
component << name
|
75
103
|
when :predicate
|
76
|
-
|
77
|
-
|
78
|
-
|
104
|
+
component << '['
|
105
|
+
component << predicate_to_path(parsed.shift) {|x| abbreviate(x)}
|
106
|
+
component << ']'
|
79
107
|
when :document
|
80
|
-
|
108
|
+
components << ""
|
81
109
|
when :function
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
110
|
+
component << parsed.shift
|
111
|
+
component << "( "
|
112
|
+
component << predicate_to_path(parsed.shift[0]) {|x| abbreviate(x)}
|
113
|
+
component << " )"
|
86
114
|
when :literal
|
87
|
-
|
115
|
+
component << quote_literal(parsed.shift)
|
88
116
|
else
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
string << ")"
|
117
|
+
component << "UNKNOWN("
|
118
|
+
component << op.inspect
|
119
|
+
component << ")"
|
93
120
|
end
|
94
121
|
end
|
95
|
-
|
96
|
-
|
122
|
+
case components
|
123
|
+
when [""]
|
124
|
+
"/"
|
125
|
+
when ["", ""]
|
126
|
+
"//"
|
127
|
+
else
|
128
|
+
components.join("/")
|
129
|
+
end
|
97
130
|
end
|
98
131
|
|
99
|
-
def expand(
|
100
|
-
|
101
|
-
|
132
|
+
def expand(path_or_parsed)
|
133
|
+
if path_or_parsed.kind_of?(String)
|
134
|
+
parsed = parse(path_or_parsed)
|
135
|
+
else
|
136
|
+
parsed = path_or_parsed
|
137
|
+
end
|
138
|
+
path = ""
|
102
139
|
document = false
|
103
|
-
while
|
104
|
-
op =
|
140
|
+
while parsed.size > 0
|
141
|
+
op = parsed.shift
|
105
142
|
case op
|
106
143
|
when :node
|
107
|
-
|
144
|
+
path << "node()"
|
108
145
|
when :attribute, :child, :following, :following_sibling,
|
109
146
|
:ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
|
110
147
|
:namespace, :preceding, :preceding_sibling, :self, :parent
|
111
|
-
|
112
|
-
|
113
|
-
|
148
|
+
path << "/" unless path.size == 0
|
149
|
+
path << op.to_s.tr("_", "-")
|
150
|
+
path << "::"
|
114
151
|
when :any
|
115
|
-
|
152
|
+
path << "*"
|
116
153
|
when :qname
|
117
|
-
prefix =
|
118
|
-
name =
|
119
|
-
|
120
|
-
|
154
|
+
prefix = parsed.shift
|
155
|
+
name = parsed.shift
|
156
|
+
path << prefix+":" if prefix.size > 0
|
157
|
+
path << name
|
121
158
|
when :predicate
|
122
|
-
|
123
|
-
|
124
|
-
|
159
|
+
path << '['
|
160
|
+
path << predicate_to_path( parsed.shift ) { |x| expand(x) }
|
161
|
+
path << ']'
|
125
162
|
when :document
|
126
163
|
document = true
|
127
164
|
else
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
string << ")"
|
165
|
+
path << "UNKNOWN("
|
166
|
+
path << op.inspect
|
167
|
+
path << ")"
|
132
168
|
end
|
133
169
|
end
|
134
|
-
|
135
|
-
|
170
|
+
path = "/"+path if document
|
171
|
+
path
|
136
172
|
end
|
137
173
|
|
138
|
-
def
|
139
|
-
|
140
|
-
case
|
174
|
+
def predicate_to_path(parsed, &block)
|
175
|
+
path = ""
|
176
|
+
case parsed[0]
|
141
177
|
when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
|
142
|
-
op =
|
178
|
+
op = parsed.shift
|
143
179
|
case op
|
144
180
|
when :eq
|
145
181
|
op = "="
|
@@ -156,36 +192,50 @@ module REXML
|
|
156
192
|
when :union
|
157
193
|
op = "|"
|
158
194
|
end
|
159
|
-
left =
|
160
|
-
right =
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
string << right
|
167
|
-
string << " "
|
195
|
+
left = predicate_to_path( parsed.shift, &block )
|
196
|
+
right = predicate_to_path( parsed.shift, &block )
|
197
|
+
path << left
|
198
|
+
path << " "
|
199
|
+
path << op.to_s
|
200
|
+
path << " "
|
201
|
+
path << right
|
168
202
|
when :function
|
169
|
-
|
170
|
-
name =
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
203
|
+
parsed.shift
|
204
|
+
name = parsed.shift
|
205
|
+
path << name
|
206
|
+
path << "("
|
207
|
+
parsed.shift.each_with_index do |argument, i|
|
208
|
+
path << ", " if i > 0
|
209
|
+
path << predicate_to_path(argument, &block)
|
210
|
+
end
|
211
|
+
path << ")"
|
175
212
|
when :literal
|
176
|
-
|
177
|
-
|
178
|
-
string << path.shift.inspect
|
179
|
-
string << " "
|
213
|
+
parsed.shift
|
214
|
+
path << quote_literal(parsed.shift)
|
180
215
|
else
|
181
|
-
|
182
|
-
string << yield( path )
|
183
|
-
string << " "
|
216
|
+
path << yield( parsed )
|
184
217
|
end
|
185
|
-
return
|
218
|
+
return path.squeeze(" ")
|
186
219
|
end
|
220
|
+
# For backward compatibility
|
221
|
+
alias_method :preciate_to_string, :predicate_to_path
|
187
222
|
|
188
223
|
private
|
224
|
+
def quote_literal( literal )
|
225
|
+
case literal
|
226
|
+
when String
|
227
|
+
# XPath 1.0 does not support escape characters.
|
228
|
+
# Assumes literal does not contain both single and double quotes.
|
229
|
+
if literal.include?("'")
|
230
|
+
"\"#{literal}\""
|
231
|
+
else
|
232
|
+
"'#{literal}'"
|
233
|
+
end
|
234
|
+
else
|
235
|
+
literal.inspect
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
189
239
|
#LocationPath
|
190
240
|
# | RelativeLocationPath
|
191
241
|
# | '/' RelativeLocationPath?
|
data/lib/rexml/rexml.rb
CHANGED
@@ -26,10 +26,12 @@
|
|
26
26
|
# - REXML::Document.
|
27
27
|
# - REXML::Element.
|
28
28
|
#
|
29
|
+
# There's also an {REXML tutorial}[doc/rexml/tutorial_rdoc.html].
|
30
|
+
#
|
29
31
|
module REXML
|
30
32
|
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
|
31
33
|
DATE = "2008/019"
|
32
|
-
VERSION = "3.
|
34
|
+
VERSION = "3.3.6"
|
33
35
|
REVISION = ""
|
34
36
|
|
35
37
|
Copyright = COPYRIGHT
|