ox 1.3.5 → 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 ox might be problematic. Click here for more details.
- data/README.md +3 -2
- data/ext/ox/parse.c +2 -0
- data/lib/ox.rb +1 -0
- data/lib/ox/element.rb +103 -0
- data/lib/ox/invalidpath.rb +10 -0
- data/lib/ox/version.rb +1 -1
- data/test/bug3.rb +21 -0
- data/test/func.rb +130 -0
- data/test/sax_example.rb +37 -0
- metadata +41 -22
data/README.md
CHANGED
@@ -26,9 +26,10 @@ A fast XML parser and Object marshaller as a Ruby gem.
|
|
26
26
|
|
27
27
|
## <a name="release">Release Notes</a>
|
28
28
|
|
29
|
-
### Release 1.
|
29
|
+
### Release 1.4.0
|
30
30
|
|
31
|
-
-
|
31
|
+
- Fixed bug in parsing the xml instruction.
|
32
|
+
- Added locate() method that provides simple and limited xpath like functionality.
|
32
33
|
|
33
34
|
## <a name="description">Description</a>
|
34
35
|
|
data/ext/ox/parse.c
CHANGED
data/lib/ox.rb
CHANGED
data/lib/ox/element.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
module Ox
|
3
|
+
|
3
4
|
# An Element represents a element of an XML document. It has a name,
|
4
5
|
# attributes, and sub-nodes.
|
5
6
|
class Element < Node
|
@@ -64,6 +65,108 @@ module Ox
|
|
64
65
|
true
|
65
66
|
end
|
66
67
|
alias == eql?
|
68
|
+
|
69
|
+
# Returns an array of Nodes or Strings that correspond to the locations
|
70
|
+
# specified by the path parameter. The path parameter describes the path
|
71
|
+
# to the return values which can be either nodes in the XML or
|
72
|
+
# attributes. The path is a relative description. There are similarities
|
73
|
+
# between the locate() method and XPath but locate does not follow the
|
74
|
+
# same rules as XPath. The syntax is meant to be simpler and more Ruby
|
75
|
+
# like.
|
76
|
+
#
|
77
|
+
# Like XPath the path delimiters are the slash (/) character. The path is
|
78
|
+
# split on the delimiter and each element of the path then describes the
|
79
|
+
# child of the current Element to traverse.
|
80
|
+
#
|
81
|
+
# Attributes are specified with an @ prefix.
|
82
|
+
#
|
83
|
+
# Each element name in the path can be followed by a bracket expression
|
84
|
+
# that narrows the paths to traverse. Supported expressions are numbers
|
85
|
+
# with a preceeding qualifier. Qualifiers are -, +, <, and >. The +
|
86
|
+
# qualifier is the default. A - qualifier indicates the index begins at
|
87
|
+
# the end of the children just like for Ruby Arrays. The < and >
|
88
|
+
# qualifiers indicates all elements either less than or greater than
|
89
|
+
# should be matched. Note that unlike XPath, the element index starts at 0
|
90
|
+
# similar to Ruby be contrary to XPath.
|
91
|
+
#
|
92
|
+
# Element names can also be wildcard characters. A * indicates any
|
93
|
+
# decendent should be followed. A ? indicates any single Element can
|
94
|
+
# match the wildcard.
|
95
|
+
#
|
96
|
+
# Examples are:
|
97
|
+
# * <code>element.locate("Family/Pete/*")</code> returns all children of the Pete Element.
|
98
|
+
# * <code>element.locate("Family/?[1]")</code> returns the first element in the Family Element.
|
99
|
+
# * <code>element.locate("Family/?[<3]")</code> returns the first 3 elements in the Family Element.
|
100
|
+
# * <code>element.locate("Family/?/@age")</code> returns the arg attribute for each child in the Family Element.
|
101
|
+
# * <code>element.locate("Family/*/@type")</code> returns the type attribute value for decendents of the Family.
|
102
|
+
#
|
103
|
+
# @param [String] path path to the Nodes to locate
|
104
|
+
def locate(path)
|
105
|
+
return [self] if path.nil?
|
106
|
+
found = []
|
107
|
+
pa = path.split('/')
|
108
|
+
alocate(pa, found)
|
109
|
+
found
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param [Array] path array of steps in a path
|
113
|
+
# @param [Array] found matching nodes
|
114
|
+
def alocate(path, found)
|
115
|
+
#puts "*** locate_dig(#{path}, #{found})"
|
116
|
+
step = path[0]
|
117
|
+
#puts "*** #{step}"
|
118
|
+
if step.start_with?('@') # attribute
|
119
|
+
raise InvalidPath.new(path) unless 1 == path.size
|
120
|
+
step = step[1..-1]
|
121
|
+
sym_step = step.to_sym
|
122
|
+
@attributes.each do |k,v|
|
123
|
+
found << v if ('?' == step or k == step or k == sym_step)
|
124
|
+
end
|
125
|
+
else # element name
|
126
|
+
if (i = step.index('[')).nil? # just name
|
127
|
+
name = step
|
128
|
+
qual = nil
|
129
|
+
else
|
130
|
+
name = step[0..i-1]
|
131
|
+
raise InvalidPath.new(path) unless step.end_with?(']')
|
132
|
+
i += 1
|
133
|
+
qual = step[i]
|
134
|
+
if '0' <= qual and qual <= '9'
|
135
|
+
qual = '+'
|
136
|
+
else
|
137
|
+
i += 1
|
138
|
+
end
|
139
|
+
index = step[i..-2].to_i
|
140
|
+
end
|
141
|
+
if '?' == name or '*' == name
|
142
|
+
match = nodes
|
143
|
+
else
|
144
|
+
match = @nodes.select { |e| e.is_a?(Element) and name == e.name }
|
145
|
+
end
|
146
|
+
unless qual.nil? or match.empty?
|
147
|
+
case qual
|
148
|
+
when '+'
|
149
|
+
match = index < match.size ? [match[index]] : []
|
150
|
+
when '-'
|
151
|
+
match = index <= match.size ? [match[-index]] : []
|
152
|
+
when '<'
|
153
|
+
match = 0 < index ? match[0..index - 1] : []
|
154
|
+
when '>'
|
155
|
+
match = index <= match.size ? match[index + 1..-1] : []
|
156
|
+
else
|
157
|
+
raise InvalidPath.new(path)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
if (1 == path.size)
|
161
|
+
match.each { |n| found << n }
|
162
|
+
elsif '*' == name
|
163
|
+
match.each { |n| n.alocate(path, found) if n.is_a?(Element) }
|
164
|
+
match.each { |n| n.alocate(path[1..-1], found) if n.is_a?(Element) }
|
165
|
+
else
|
166
|
+
match.each { |n| n.alocate(path[1..-1], found) if n.is_a?(Element) }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
67
170
|
|
68
171
|
end # Element
|
69
172
|
end # Ox
|
data/lib/ox/version.rb
CHANGED
data/test/bug3.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
|
3
|
+
$: << '../lib'
|
4
|
+
$: << '../ext'
|
5
|
+
|
6
|
+
require 'ox'
|
7
|
+
|
8
|
+
def name_it()
|
9
|
+
begin
|
10
|
+
"x".foo
|
11
|
+
rescue Exception => e
|
12
|
+
#puts e.message
|
13
|
+
xml = Ox.dump(e, effort: :tolerant)
|
14
|
+
puts xml
|
15
|
+
o = Ox.load(xml, mode: :object)
|
16
|
+
puts o.message
|
17
|
+
puts Ox.dump(e)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
name_it()
|
data/test/func.rb
CHANGED
@@ -383,7 +383,137 @@ class Func < ::Test::Unit::TestCase
|
|
383
383
|
obj = Ox.load(xml, :mode => :object) # should convert it to an object
|
384
384
|
assert_equal(nil, obj)
|
385
385
|
end
|
386
|
+
|
387
|
+
def locate_xml()
|
388
|
+
%{<?xml?>
|
389
|
+
<Family real="false">
|
390
|
+
<Pete age="57" type="male">
|
391
|
+
<Kid1 age="32"/>
|
392
|
+
<Kid2 age="31"/>
|
393
|
+
</Pete>
|
394
|
+
</Family>
|
395
|
+
}
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_locate_self
|
399
|
+
doc = Ox.parse(locate_xml)
|
400
|
+
nodes = doc.locate(nil)
|
401
|
+
assert_equal(doc, nodes[0])
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_locate_top
|
405
|
+
doc = Ox.parse(locate_xml)
|
406
|
+
nodes = doc.locate('Family')
|
407
|
+
assert_equal([doc.nodes[0]], nodes)
|
408
|
+
end
|
409
|
+
|
410
|
+
def test_locate_top_wild
|
411
|
+
doc = Ox.parse(locate_xml)
|
412
|
+
nodes = doc.locate('?')
|
413
|
+
assert_equal([doc.nodes[0]], nodes)
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_locate_child
|
417
|
+
doc = Ox.parse(locate_xml)
|
418
|
+
|
419
|
+
nodes = doc.locate('Family/?')
|
420
|
+
assert_equal(['Pete'], nodes.map { |n| n.name })
|
421
|
+
|
422
|
+
nodes = doc.locate('Family/?/?')
|
423
|
+
assert_equal(['Kid1', 'Kid2'], nodes.map { |n| n.name })
|
424
|
+
|
425
|
+
nodes = doc.locate('Family/Pete/?')
|
426
|
+
assert_equal(['Kid1', 'Kid2'], nodes.map { |n| n.name })
|
427
|
+
|
428
|
+
nodes = doc.locate('Family/Makie/?')
|
429
|
+
assert_equal([], nodes.map { |n| n.name })
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_locate_child_wild_wild
|
433
|
+
doc = Ox.parse(locate_xml)
|
434
|
+
nodes = doc.locate('Family/?/?')
|
435
|
+
assert_equal(['Kid1', 'Kid2'], nodes.map { |n| n.name })
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_locate_child_wild
|
439
|
+
doc = Ox.parse(locate_xml)
|
440
|
+
nodes = doc.locate('Family/Pete/?')
|
441
|
+
assert_equal(['Kid1', 'Kid2'], nodes.map { |n| n.name })
|
442
|
+
end
|
443
|
+
|
444
|
+
def test_locate_child_wild_missing
|
445
|
+
doc = Ox.parse(locate_xml)
|
446
|
+
nodes = doc.locate('Family/Makie/?')
|
447
|
+
assert_equal([], nodes.map { |n| n.name })
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_locate_attribute
|
451
|
+
doc = Ox.parse(locate_xml)
|
386
452
|
|
453
|
+
nodes = doc.locate('Family/@?')
|
454
|
+
assert_equal(['false'], nodes)
|
455
|
+
|
456
|
+
nodes = doc.locate('Family/@real')
|
457
|
+
assert_equal(['false'], nodes)
|
458
|
+
|
459
|
+
nodes = doc.locate('Family/Pete/@?')
|
460
|
+
assert_equal(['57', 'male'], nodes.sort)
|
461
|
+
|
462
|
+
nodes = doc.locate('Family/Pete/@age')
|
463
|
+
assert_equal(['57'], nodes)
|
464
|
+
|
465
|
+
nodes = doc.locate('Family/Makie/@?')
|
466
|
+
assert_equal([], nodes)
|
467
|
+
|
468
|
+
nodes = doc.locate('Family/Pete/?/@age')
|
469
|
+
assert_equal(['31', '32'], nodes.sort)
|
470
|
+
|
471
|
+
nodes = doc.locate('Family/*/@age')
|
472
|
+
assert_equal(['31', '32', '57'], nodes.sort)
|
473
|
+
|
474
|
+
nodes = doc.locate('*/@?')
|
475
|
+
assert_equal(['31', '32', '57', 'false', 'male'], nodes.sort)
|
476
|
+
|
477
|
+
assert_raise(::Ox::InvalidPath) {
|
478
|
+
nodes = doc.locate('Family/@age/?')
|
479
|
+
}
|
480
|
+
|
481
|
+
assert_raise(::Ox::InvalidPath) {
|
482
|
+
nodes = doc.locate('Family/?[/?')
|
483
|
+
}
|
484
|
+
end
|
485
|
+
|
486
|
+
def test_locate_qual_index
|
487
|
+
doc = Ox.parse(locate_xml)
|
488
|
+
nodes = doc.locate('Family/Pete/?[0]')
|
489
|
+
assert_equal(['Kid1'], nodes.map { |e| e.name } )
|
490
|
+
nodes = doc.locate('Family/Pete/?[1]')
|
491
|
+
assert_equal(['Kid2'], nodes.map { |e| e.name } )
|
492
|
+
end
|
493
|
+
|
494
|
+
def test_locate_qual_less
|
495
|
+
doc = Ox.parse(locate_xml)
|
496
|
+
nodes = doc.locate('Family/Pete/?[<1]')
|
497
|
+
assert_equal(['Kid1'], nodes.map { |e| e.name } )
|
498
|
+
end
|
499
|
+
|
500
|
+
def test_locate_qual_great
|
501
|
+
doc = Ox.parse(locate_xml)
|
502
|
+
nodes = doc.locate('Family/Pete/?[>0]')
|
503
|
+
assert_equal(['Kid2'], nodes.map { |e| e.name } )
|
504
|
+
end
|
505
|
+
|
506
|
+
def test_locate_qual_last
|
507
|
+
doc = Ox.parse(locate_xml)
|
508
|
+
nodes = doc.locate('Family/Pete/?[-1]')
|
509
|
+
assert_equal(['Kid2'], nodes.map { |e| e.name } )
|
510
|
+
end
|
511
|
+
|
512
|
+
def test_locate_qual_last_attr
|
513
|
+
doc = Ox.parse(locate_xml)
|
514
|
+
nodes = doc.locate('Family/Pete/?[-1]/@age')
|
515
|
+
assert_equal(['31'], nodes )
|
516
|
+
end
|
387
517
|
end
|
388
518
|
|
389
519
|
class Bag
|
data/test/sax_example.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
|
3
|
+
$: << '../lib'
|
4
|
+
$: << '../ext'
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
require 'ox'
|
8
|
+
|
9
|
+
class Sample < ::Ox::Sax
|
10
|
+
def start_element(name); puts "start: #{name}"; end
|
11
|
+
def end_element(name); puts "end: #{name}"; end
|
12
|
+
def attr(name, value); puts " #{name} => #{value}"; end
|
13
|
+
def text(value); puts "text #{value}"; end
|
14
|
+
end
|
15
|
+
|
16
|
+
io = StringIO.new(%{
|
17
|
+
<top name="sample">
|
18
|
+
<middle name="second">
|
19
|
+
<bottom name="third"/>
|
20
|
+
</middle>
|
21
|
+
</top>
|
22
|
+
})
|
23
|
+
|
24
|
+
handler = Sample.new()
|
25
|
+
Ox.sax_parse(handler, io)
|
26
|
+
|
27
|
+
# outputs
|
28
|
+
# start: top
|
29
|
+
# name => sample
|
30
|
+
# start: middle
|
31
|
+
# name => second
|
32
|
+
# start: bottom
|
33
|
+
# name => third
|
34
|
+
# end: bottom
|
35
|
+
# end: middle
|
36
|
+
# end: top
|
37
|
+
|
metadata
CHANGED
@@ -1,30 +1,39 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ox
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 1.4.0
|
6
10
|
platform: ruby
|
7
|
-
authors:
|
11
|
+
authors:
|
8
12
|
- Peter Ohler
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
15
|
cert_chain: []
|
12
|
-
|
16
|
+
|
17
|
+
date: 2011-10-18 00:00:00 +09:00
|
18
|
+
default_executable:
|
13
19
|
dependencies: []
|
20
|
+
|
14
21
|
description: A fast XML parser and object serializer that uses only standard C lib.
|
15
22
|
email: peter@ohler.com
|
16
23
|
executables: []
|
17
|
-
|
24
|
+
|
25
|
+
extensions:
|
18
26
|
- ext/ox/extconf.rb
|
19
|
-
extra_rdoc_files:
|
27
|
+
extra_rdoc_files:
|
20
28
|
- README.md
|
21
|
-
files:
|
29
|
+
files:
|
22
30
|
- lib/ox/bag.rb
|
23
31
|
- lib/ox/cdata.rb
|
24
32
|
- lib/ox/comment.rb
|
25
33
|
- lib/ox/doctype.rb
|
26
34
|
- lib/ox/document.rb
|
27
35
|
- lib/ox/element.rb
|
36
|
+
- lib/ox/invalidpath.rb
|
28
37
|
- lib/ox/node.rb
|
29
38
|
- lib/ox/sax.rb
|
30
39
|
- lib/ox/version.rb
|
@@ -47,6 +56,7 @@ files:
|
|
47
56
|
- ext/ox/sax.c
|
48
57
|
- test/bug1.rb
|
49
58
|
- test/bug2.rb
|
59
|
+
- test/bug3.rb
|
50
60
|
- test/cache16_test.rb
|
51
61
|
- test/cache8_test.rb
|
52
62
|
- test/cache_test.rb
|
@@ -74,36 +84,45 @@ files:
|
|
74
84
|
- test/perf_sax.rb
|
75
85
|
- test/perf_write.rb
|
76
86
|
- test/sample.rb
|
87
|
+
- test/sax_example.rb
|
77
88
|
- test/sax_test.rb
|
78
89
|
- test/test.rb
|
79
90
|
- test/Sample.graffle
|
80
91
|
- LICENSE
|
81
92
|
- README.md
|
93
|
+
has_rdoc: true
|
82
94
|
homepage: https://github.com/ohler55/ox
|
83
95
|
licenses: []
|
96
|
+
|
84
97
|
post_install_message:
|
85
|
-
rdoc_options:
|
98
|
+
rdoc_options:
|
86
99
|
- --main
|
87
100
|
- README.md
|
88
|
-
require_paths:
|
101
|
+
require_paths:
|
89
102
|
- lib
|
90
103
|
- ext
|
91
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
105
|
none: false
|
93
|
-
requirements:
|
94
|
-
- -
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
|
97
|
-
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
version: "0"
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
113
|
none: false
|
99
|
-
requirements:
|
100
|
-
- -
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
103
120
|
requirements: []
|
121
|
+
|
104
122
|
rubyforge_project: ox
|
105
|
-
rubygems_version: 1.
|
123
|
+
rubygems_version: 1.3.7
|
106
124
|
signing_key:
|
107
125
|
specification_version: 3
|
108
126
|
summary: A fast XML parser and object serializer.
|
109
127
|
test_files: []
|
128
|
+
|