xml_mapper 0.4.1 → 0.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.
- 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
|