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 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 # 1:1 - maps xpaths title and version_title to attribute keys
50
- integer :released_in # converts value to an integer
51
- text :country, :after_map => :upcase # calls after_map method on extracted value if value responds to the method
52
- text :released_on, :after_map => :parse_date # calls after_map method defined in Mapper class when value does not respond
53
- boolean :allows_streaming # maps Y, y, yes, true => true, N, n, no, false => false
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 # adds mapping for xpath "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 # use the name of xml nodes for mappings
61
- node_name :role # map name of xml node to :role
62
- inner_text :name # map inner_text of xml node to :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 # maps xpath "tracks/track" to array with key :tracks
66
- attribute :code => :isrc # map xml attribute "code" to :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 # checks if a node with the xpath exists
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 # is called after attributes are extracted, self references the extracted attributes
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
- { :title=>"Black on Both Sides", :allows_streaming=>true, :version_title=>"Extended Edition",
91
- :xml_path=>"/Users/tobias/Projects/xml_mapper/spec/fixtures/base.xml", :tracks_count=>2, :released_in=>1999,
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
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
- hash.merge(mapping[:key] => value_from_doc_and_mapping(doc, mapping))
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
- node.inner_text if node
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
- { :track_title => "Fear Not of Man", :track_number => 1, :disk_number => 1, :explicit_lyrics => true, :isrc => "1234" },
26
- { :track_title => "Hip Hop", :track_number => 2, :disk_number => 1, :explicit_lyrics => false, :isrc => "2345" },
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
@@ -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
@@ -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.1"
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-01}
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: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 1
10
- version: 0.4.1
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-01 00:00:00 +01:00
18
+ date: 2010-12-02 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency