xml_mapper 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +32 -25
- data/VERSION +1 -1
- data/lib/xml_mapper.rb +16 -2
- data/spec/example_spec.rb +10 -2
- data/spec/fixtures/base.xml +4 -0
- data/spec/my_mapper.rb +5 -1
- data/spec/xml_mapper_spec.rb +16 -0
- data/xml_mapper.gemspec +2 -2
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -22,6 +22,7 @@ Declarative mapping of XML files to ruby attributes
|
|
22
22
|
<tracks>
|
23
23
|
<track code="1234">
|
24
24
|
<title>Fear Not of Man</title>
|
25
|
+
<version_title></version_title>
|
25
26
|
<number>1</number>
|
26
27
|
<disk>1</number>
|
27
28
|
<explicit_lyrics />
|
@@ -31,8 +32,11 @@ Declarative mapping of XML files to ruby attributes
|
|
31
32
|
</track>
|
32
33
|
<track code="2345">
|
33
34
|
<title>Hip Hop</title>
|
35
|
+
<version_title>Album Version</version_title>
|
34
36
|
<number>2</number>
|
35
37
|
<disk>1</number>
|
38
|
+
<performer>Mos Def</performer>
|
39
|
+
<producer>DJ Premier</producer>
|
36
40
|
<not_streamable_in>
|
37
41
|
<country>at</country>
|
38
42
|
</not_streamable_in>
|
@@ -46,32 +50,36 @@ Declarative mapping of XML files to ruby attributes
|
|
46
50
|
require "date"
|
47
51
|
|
48
52
|
class MyMapper < XmlMapper
|
49
|
-
text :title, :version_title
|
50
|
-
integer :released_in
|
51
|
-
text :country, :after_map => :upcase
|
52
|
-
text :released_on, :after_map => :parse_date
|
53
|
-
boolean :allows_streaming
|
53
|
+
text :title, :version_title # 1:1 - maps xpaths title and version_title to attribute keys
|
54
|
+
integer :released_in # converts value to an integer
|
55
|
+
text :country, :after_map => :upcase # calls after_map method on extracted value if value responds to the method
|
56
|
+
text :released_on, :after_map => :parse_date # calls after_map method defined in Mapper class when value does not respond
|
57
|
+
boolean :allows_streaming # maps 1, Y, y, yes, true => true, 0, N, n, no, false => false
|
54
58
|
|
55
59
|
within :artist do
|
56
|
-
text :name => :artist_name
|
60
|
+
text :name => :artist_name # adds mapping for xpath "artist/name"
|
57
61
|
integer :id => :artist_id
|
58
62
|
end
|
59
63
|
|
60
|
-
many "contributions/*" => :contributions do
|
61
|
-
node_name :role
|
62
|
-
inner_text :name
|
64
|
+
many "contributions/*" => :contributions do # use the name of xml nodes for mappings
|
65
|
+
node_name :role # map name of xml node to :role
|
66
|
+
inner_text :name # map inner_text of xml node to :name
|
63
67
|
end
|
64
68
|
|
65
|
-
many "tracks/track" => :tracks do
|
66
|
-
attribute :code => :isrc
|
69
|
+
many "tracks/track" => :tracks do # maps xpath "tracks/track" to array with key :tracks
|
70
|
+
attribute :code => :isrc # map xml attribute "code" to :isrc
|
67
71
|
text :title => :track_title
|
72
|
+
text :version_title
|
68
73
|
integer :number => :track_number
|
69
74
|
integer :disk => :disk_number
|
70
|
-
exists :explicit_lyrics
|
75
|
+
exists :explicit_lyrics # checks if a node with the xpath exists
|
71
76
|
not_exists "not_streamable_in/country[text()='de']" => :allows_streaming
|
77
|
+
|
78
|
+
text :performer => { :contributions => :performer } # assigns to content at xpath :performer to attributes[:contributions][:performer]
|
79
|
+
text :producer => { :contributions => :producer } # assigns to content at xpath :performer to attributes[:contributions][:producer]
|
72
80
|
end
|
73
81
|
|
74
|
-
after_map do
|
82
|
+
after_map do # is called after attributes are extracted, self references the extracted attributes
|
75
83
|
self[:tracks_count] = self[:tracks].length
|
76
84
|
end
|
77
85
|
|
@@ -87,21 +95,20 @@ Declarative mapping of XML files to ruby attributes
|
|
87
95
|
* MyMapper.attributes_from_xml_path(xml) (also sets :xml_path)
|
88
96
|
|
89
97
|
== Output
|
90
|
-
{
|
91
|
-
:
|
92
|
-
:released_on=>#<Date: 4902927/2,0,2299161>, :artist_name=>"Mos Def",
|
93
|
-
:contributions=>[
|
94
|
-
{:name=>"Mos Def", :role=>"artist"}, {:name=>"DJ Premier", :role=>"producer"}
|
95
|
-
],
|
96
|
-
:artist_id=>1212, :country=>"DE",
|
98
|
+
{
|
99
|
+
:title=>"Black on Both Sides", :allows_streaming=>true, :version_title=>"Extended Edition",
|
97
100
|
:tracks=>[
|
98
|
-
{ :track_title=>"Fear Not of Man", :allows_streaming=>false, :track_number=>1, :disk_number=>1,
|
99
|
-
:explicit_lyrics=>true, :isrc=>"1234"
|
101
|
+
{ :track_title=>"Fear Not of Man", :allows_streaming=>false, :track_number=>1, :version_title=>nil, :disk_number=>1,
|
102
|
+
:explicit_lyrics=>true, :contributions=>{:performer=>nil, :producer=>nil}, :isrc=>"1234"
|
100
103
|
},
|
101
|
-
{ :track_title=>"Hip Hop", :allows_streaming=>true, :track_number=>2, :disk_number=>1,
|
102
|
-
:explicit_lyrics=>false, :isrc=>"2345"
|
104
|
+
{ :track_title=>"Hip Hop", :allows_streaming=>true, :track_number=>2, :version_title=>"Album Version", :disk_number=>1,
|
105
|
+
:explicit_lyrics=>false, :contributions=>{:performer=>"Mos Def", :producer=>"DJ Premier"}, :isrc=>"2345"
|
103
106
|
}
|
104
|
-
]
|
107
|
+
],
|
108
|
+
:tracks_count=>2, :released_in=>1999, :xml_path=>"/Users/tobias/Projects/xml_mapper/spec/fixtures/base.xml",
|
109
|
+
:released_on=>#<Date: 4902927/2,0,2299161>, :artist_name=>"Mos Def",
|
110
|
+
:contributions=>[ {:name=>"Mos Def", :role=>"artist"}, {:name=>"DJ Premier", :role=>"producer"} ]
|
111
|
+
:artist_id=>1212, :country=>"DE"
|
105
112
|
}
|
106
113
|
|
107
114
|
== Contributing to xml_mapper
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.2
|
data/lib/xml_mapper.rb
CHANGED
@@ -123,13 +123,25 @@ class XmlMapper
|
|
123
123
|
doc = xml_or_doc.is_a?(Nokogiri::XML::Node) ? xml_or_doc : Nokogiri::XML(xml_or_doc)
|
124
124
|
doc = doc.root if doc.respond_to?(:root)
|
125
125
|
atts = self.mappings.inject(xml_path.nil? ? {} : { :xml_path => xml_path }) do |hash, mapping|
|
126
|
-
|
126
|
+
if (value = value_from_doc_and_mapping(doc, mapping)) != :not_found
|
127
|
+
add_value_to_hash(hash, mapping[:key], value)
|
128
|
+
end
|
127
129
|
end
|
128
130
|
atts.instance_eval(&self.after_map_block) if self.after_map_block
|
129
131
|
atts
|
130
132
|
end
|
131
133
|
end
|
132
134
|
|
135
|
+
def add_value_to_hash(hash, key_or_hash, value)
|
136
|
+
if key_or_hash.is_a?(Hash)
|
137
|
+
hash[key_or_hash.keys.first] ||= Hash.new
|
138
|
+
add_value_to_hash(hash[key_or_hash.keys.first], key_or_hash.values.first, value)
|
139
|
+
else
|
140
|
+
hash.merge!(key_or_hash => value)
|
141
|
+
end
|
142
|
+
hash
|
143
|
+
end
|
144
|
+
|
133
145
|
def value_from_doc_and_mapping(doc, mapping)
|
134
146
|
if mapping[:type] == :many
|
135
147
|
mapping[:options][:mapper].attributes_from_xml(doc.search(mapping[:xpath]).to_a)
|
@@ -170,7 +182,9 @@ class XmlMapper
|
|
170
182
|
end
|
171
183
|
|
172
184
|
def inner_text_for_node(node)
|
173
|
-
|
185
|
+
if node
|
186
|
+
node.inner_text.length == 0 ? nil : node.inner_text
|
187
|
+
end
|
174
188
|
end
|
175
189
|
|
176
190
|
MAPPINGS = {
|
data/spec/example_spec.rb
CHANGED
@@ -22,8 +22,16 @@ describe "ExampleSpec" do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
[
|
25
|
-
{
|
26
|
-
|
25
|
+
{
|
26
|
+
:track_title => "Fear Not of Man", :track_number => 1, :disk_number => 1, :explicit_lyrics => true, :isrc => "1234",
|
27
|
+
:version_title => nil
|
28
|
+
},
|
29
|
+
{
|
30
|
+
:track_title => "Hip Hop", :track_number => 2, :disk_number => 1, :explicit_lyrics => false, :isrc => "2345",
|
31
|
+
:version_title => "Album Version", :contributions => {
|
32
|
+
:producer => "DJ Premier", :performer => "Mos Def"
|
33
|
+
}
|
34
|
+
},
|
27
35
|
].each_with_index do |hash, offset|
|
28
36
|
hash.each do |key, value|
|
29
37
|
it "extracts #{value.inspect} for #{key} for track with offset #{offset}" do
|
data/spec/fixtures/base.xml
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
<tracks>
|
17
17
|
<track code="1234">
|
18
18
|
<title>Fear Not of Man</title>
|
19
|
+
<version_title></version_title>
|
19
20
|
<number>1</number>
|
20
21
|
<disk>1</number>
|
21
22
|
<explicit_lyrics />
|
@@ -25,8 +26,11 @@
|
|
25
26
|
</track>
|
26
27
|
<track code="2345">
|
27
28
|
<title>Hip Hop</title>
|
29
|
+
<version_title>Album Version</version_title>
|
28
30
|
<number>2</number>
|
29
31
|
<disk>1</number>
|
32
|
+
<performer>Mos Def</performer>
|
33
|
+
<producer>DJ Premier</producer>
|
30
34
|
<not_streamable_in>
|
31
35
|
<country>at</country>
|
32
36
|
</not_streamable_in>
|
data/spec/my_mapper.rb
CHANGED
@@ -6,7 +6,7 @@ class MyMapper < XmlMapper
|
|
6
6
|
integer :released_in # converts value to an integer
|
7
7
|
text :country, :after_map => :upcase # calls after_map method on extracted value if value responds to the method
|
8
8
|
text :released_on, :after_map => :parse_date # calls after_map method defined in Mapper class when value does not respond
|
9
|
-
boolean :allows_streaming # maps Y, y, yes, true => true, N, n, no, false => false
|
9
|
+
boolean :allows_streaming # maps 1, Y, y, yes, true => true, 0, N, n, no, false => false
|
10
10
|
|
11
11
|
within :artist do
|
12
12
|
text :name => :artist_name # adds mapping for xpath "artist/name"
|
@@ -21,10 +21,14 @@ class MyMapper < XmlMapper
|
|
21
21
|
many "tracks/track" => :tracks do # maps xpath "tracks/track" to array with key :tracks
|
22
22
|
attribute :code => :isrc # map xml attribute "code" to :isrc
|
23
23
|
text :title => :track_title
|
24
|
+
text :version_title
|
24
25
|
integer :number => :track_number
|
25
26
|
integer :disk => :disk_number
|
26
27
|
exists :explicit_lyrics # checks if a node with the xpath exists
|
27
28
|
not_exists "not_streamable_in/country[text()='de']" => :allows_streaming
|
29
|
+
|
30
|
+
text :performer => { :contributions => :performer }
|
31
|
+
text :producer => { :contributions => :producer }
|
28
32
|
end
|
29
33
|
|
30
34
|
after_map do # is called after attributes are extracted, self references the extracted attributes
|
data/spec/xml_mapper_spec.rb
CHANGED
@@ -72,6 +72,22 @@ describe "XmlMapper" do
|
|
72
72
|
@mapper.attributes_from_xml(@xml).should == { :title => "Black on Both Sides", :artist_name => "Mos Def" }
|
73
73
|
end
|
74
74
|
|
75
|
+
it "sets value to nil when value was empty string" do
|
76
|
+
@mapper.add_mapping(:text, :artist_name)
|
77
|
+
@mapper.attributes_from_xml("<album><artist_name></artist_name></album>").should == { :artist_name => nil }
|
78
|
+
end
|
79
|
+
|
80
|
+
it "assigns found keys to nested attributes" do
|
81
|
+
@mapper.add_mapping(:text, :artist_name => { :meta => :artist_name })
|
82
|
+
@mapper.add_mapping(:text, :title => { :meta => :title })
|
83
|
+
@mapper.attributes_from_xml(@xml).should == {
|
84
|
+
:meta => {
|
85
|
+
:artist_name => "Mos Def",
|
86
|
+
:title => "Black on Both Sides"
|
87
|
+
}
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
75
91
|
describe "#exists" do
|
76
92
|
it "returns true when node exists" do
|
77
93
|
xml = %(<album><title>Black on Both Sides</title><rights><country>DE</country></rights></album>)
|
data/xml_mapper.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{xml_mapper}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tobias Schwab"]
|
12
|
-
s.date = %q{2010-12-
|
12
|
+
s.date = %q{2010-12-02}
|
13
13
|
s.description = %q{Declarative XML to Ruby mapping}
|
14
14
|
s.email = %q{tobias.schwab@dynport.de}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml_mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tobias Schwab
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-02 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|