Class: XmlMapper
- Inherits:
-
Object
- Object
- XmlMapper
- Defined in:
- lib/xml_mapper.rb,
lib/xml_mapper_hash.rb
Defined Under Namespace
Classes: XmlMapperHash
Constant Summary collapse
- TYPE_TO_AFTER_CODE =
{ :integer => :to_i, :boolean => :string_to_boolean }
- MAPPINGS =
{ "true" => true, "false" => false, "yes" => true, "no" => false, "y" => true, "n" => false, "1" => true, "0" => false }
Class Attribute Summary collapse
-
.mapper ⇒ Object
Returns the value of attribute mapper.
Instance Attribute Summary collapse
-
#after_map_block ⇒ Object
Returns the value of attribute after_map_block.
-
#mappings ⇒ Object
Returns the value of attribute mappings.
-
#selector_mode ⇒ Object
Returns the value of attribute selector_mode.
-
#within_xpath ⇒ Object
Returns the value of attribute within_xpath.
Class Method Summary collapse
- .add_mapper_to_args(args, mapper) ⇒ Object
- .after_map(&block) ⇒ Object
- .attributes_from_superclass(xml, method = :attributes_from_xml) ⇒ Object
- .attributes_from_xml(xml) ⇒ Object
- .attributes_from_xml_path(path, xml = nil) ⇒ Object
- .capture_submapping(&block) ⇒ Object
- .include_mapper(clazz) ⇒ Object
- .many(*args, &block) ⇒ Object
- .selector_mode(style) ⇒ Object
- .within(xpath, &block) ⇒ Object
Instance Method Summary collapse
- #add_mapping(type, *args) ⇒ Object
- #add_single_mapping(type, xpath_or_attribute, key, options = {}) ⇒ Object
- #add_value_to_hash(hash, key_or_hash, value) ⇒ Object
- #add_with_to_xpath(xpath) ⇒ Object
- #after_map(&block) ⇒ Object
- #apply_after_map_to_value(value, mapping) ⇒ Object
- #attributes_from_xml(xml_or_doc, xml_path = nil) ⇒ Object
- #attributes_from_xml_path(path) ⇒ Object
- #extract_options_from_args(args) ⇒ Object
-
#initialize ⇒ XmlMapper
constructor
A new instance of XmlMapper.
- #inner_text_for_node(node) ⇒ Object
- #parse_date(text) ⇒ Object
- #parse_duration(string) ⇒ Object
- #string_to_boolean(value) ⇒ Object
- #value_from_doc_and_mapping(doc, mapping, xml_path = nil) ⇒ Object
Constructor Details
#initialize ⇒ XmlMapper
Returns a new instance of XmlMapper.
87 88 89 90 |
# File 'lib/xml_mapper.rb', line 87 def initialize self.mappings = [] self.selector_mode = :search end |
Class Attribute Details
.mapper ⇒ Object
Returns the value of attribute mapper.
10 11 12 |
# File 'lib/xml_mapper.rb', line 10 def mapper @mapper end |
Instance Attribute Details
#after_map_block ⇒ Object
Returns the value of attribute after_map_block.
7 8 9 |
# File 'lib/xml_mapper.rb', line 7 def after_map_block @after_map_block end |
#mappings ⇒ Object
Returns the value of attribute mappings.
7 8 9 |
# File 'lib/xml_mapper.rb', line 7 def mappings @mappings end |
#selector_mode ⇒ Object
Returns the value of attribute selector_mode.
7 8 9 |
# File 'lib/xml_mapper.rb', line 7 def selector_mode @selector_mode end |
#within_xpath ⇒ Object
Returns the value of attribute within_xpath.
7 8 9 |
# File 'lib/xml_mapper.rb', line 7 def within_xpath @within_xpath end |
Class Method Details
.add_mapper_to_args(args, mapper) ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/xml_mapper.rb', line 66 def add_mapper_to_args(args, mapper) if args.length > 1 && args.last.is_a?(Hash) args.last[:mapper] = mapper else args << { :mapper => mapper } end end |
.after_map(&block) ⇒ Object
25 26 27 |
# File 'lib/xml_mapper.rb', line 25 def after_map(&block) mapper.after_map(&block) end |
.attributes_from_superclass(xml, method = :attributes_from_xml) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/xml_mapper.rb', line 39 def attributes_from_superclass(xml, method = :attributes_from_xml) if self.superclass && self.superclass.respond_to?(:mapper) attributes = self.superclass.mapper.send(method, xml) attributes.delete(:xml_path) attributes else {} end end |
.attributes_from_xml(xml) ⇒ Object
35 36 37 |
# File 'lib/xml_mapper.rb', line 35 def attributes_from_xml(xml) attributes_from_superclass(xml, :attributes_from_xml).merge(mapper.attributes_from_xml(xml)) end |
.attributes_from_xml_path(path, xml = nil) ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/xml_mapper.rb', line 49 def attributes_from_xml_path(path, xml = nil) if xml attributes_from_superclass(xml, :attributes_from_xml).merge(mapper.attributes_from_xml(xml, path)) else attributes_from_superclass(path, :attributes_from_xml_path).merge(mapper.attributes_from_xml_path(path)) end end |
.capture_submapping(&block) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/xml_mapper.rb', line 57 def capture_submapping(&block) saved_mapper = self.mapper self.mapper = self.new self.instance_eval(&block) captured_mapper = self.mapper self.mapper = saved_mapper captured_mapper end |
.include_mapper(clazz) ⇒ Object
82 83 84 |
# File 'lib/xml_mapper.rb', line 82 def include_mapper(clazz) self.mapper.mappings += clazz.mapper.mappings end |
.many(*args, &block) ⇒ Object
29 30 31 32 33 |
# File 'lib/xml_mapper.rb', line 29 def many(*args, &block) sub_mapper = block_given? ? capture_submapping(&block) : nil add_mapper_to_args(args, sub_mapper) mapper.add_mapping(:many, *args) end |
.selector_mode(style) ⇒ Object
78 79 80 |
# File 'lib/xml_mapper.rb', line 78 def selector_mode(style) self.mapper.selector_mode = style end |
.within(xpath, &block) ⇒ Object
18 19 20 21 22 23 |
# File 'lib/xml_mapper.rb', line 18 def within(xpath, &block) self.mapper.within_xpath ||= [] self.mapper.within_xpath << xpath self.instance_eval(&block) self.mapper.within_xpath.pop end |
Instance Method Details
#add_mapping(type, *args) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/xml_mapper.rb', line 96 def add_mapping(type, *args) = (args) if args.first.is_a?(Hash) if after_map_method = args.first.delete(:after_map) .merge!(:after_map => after_map_method) end args.first.map { |xpath, key| add_single_mapping(type, xpath, key, ) } else args.map { |arg| add_single_mapping(type, arg, arg, ) } end end |
#add_single_mapping(type, xpath_or_attribute, key, options = {}) ⇒ Object
112 113 114 115 116 117 118 119 120 |
# File 'lib/xml_mapper.rb', line 112 def add_single_mapping(type, xpath_or_attribute, key, = {}) mappings = { :type => type, :key => key, :options => } xpath = type == :attribute ? nil : xpath_or_attribute if type == :attribute mappings[:attribute] = xpath_or_attribute.to_s end mappings[:xpath] = add_with_to_xpath(xpath) self.mappings << mappings end |
#add_value_to_hash(hash, key_or_hash, value) ⇒ Object
151 152 153 154 155 156 157 158 159 |
# File 'lib/xml_mapper.rb', line 151 def add_value_to_hash(hash, key_or_hash, value) if key_or_hash.is_a?(Hash) hash[key_or_hash.keys.first] ||= Hash.new add_value_to_hash(hash[key_or_hash.keys.first], key_or_hash.values.first, value) else hash.merge!(key_or_hash => value) end hash end |
#add_with_to_xpath(xpath) ⇒ Object
122 123 124 |
# File 'lib/xml_mapper.rb', line 122 def add_with_to_xpath(xpath) [self.within_xpath, xpath].flatten.compact.join("/") end |
#after_map(&block) ⇒ Object
108 109 110 |
# File 'lib/xml_mapper.rb', line 108 def after_map(&block) self.after_map_block = block end |
#apply_after_map_to_value(value, mapping) ⇒ Object
189 190 191 192 193 194 195 196 197 198 |
# File 'lib/xml_mapper.rb', line 189 def apply_after_map_to_value(value, mapping) after_mappings = [TYPE_TO_AFTER_CODE[mapping[:type]], mapping[:options][:after_map]].compact if value after_mappings.each do |after_map| value = value.send(after_map) if value.respond_to?(after_map) value = self.send(after_map, value) if self.respond_to?(after_map) end end value end |
#attributes_from_xml(xml_or_doc, xml_path = nil) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/xml_mapper.rb', line 135 def attributes_from_xml(xml_or_doc, xml_path = nil) if xml_or_doc.is_a?(Array) xml_or_doc.map { |doc| attributes_from_xml(doc, xml_path) } else doc = xml_or_doc.is_a?(Nokogiri::XML::Node) ? xml_or_doc : Nokogiri::XML(xml_or_doc.gsub(/xmlns=[\"\'].*?[\"\']/, "")) # get rid of xml namespaces, quick and dirty doc = doc.root if doc.respond_to?(:root) atts = self.mappings.inject(XmlMapperHash.from_path_and_node(xml_path, doc)) do |hash, mapping| if (value = value_from_doc_and_mapping(doc, mapping, xml_path)) != :not_found add_value_to_hash(hash, mapping[:key], value) end end atts.instance_eval(&self.after_map_block) if self.after_map_block atts end end |
#attributes_from_xml_path(path) ⇒ Object
126 127 128 |
# File 'lib/xml_mapper.rb', line 126 def attributes_from_xml_path(path) attributes_from_xml(File.read(path), path) end |
#extract_options_from_args(args) ⇒ Object
92 93 94 |
# File 'lib/xml_mapper.rb', line 92 def (args) args.length > 1 && args.last.is_a?(Hash) ? args.pop : {} end |
#inner_text_for_node(node) ⇒ Object
200 201 202 203 204 |
# File 'lib/xml_mapper.rb', line 200 def inner_text_for_node(node) if node node.inner_text.length == 0 ? nil : node.inner_text end end |
#parse_date(text) ⇒ Object
232 233 234 235 |
# File 'lib/xml_mapper.rb', line 232 def parse_date(text) text.to_s.strip.length > 0 ? Date.parse(text.to_s.strip) : nil rescue end |
#parse_duration(string) ⇒ Object
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/xml_mapper.rb', line 221 def parse_duration(string) return string.to_i if string.match(/^\d+$/) string = "00:#{string}" if string.match(/^(\d+):(\d+)$/) string = string.to_s.gsub(/PT(\d+M.*)/,"PT0H\\1") # insert 0H into PT3M12S, for example: PT0H3M12S if string.match(/^PT(\d+)H(\d+)M(\d+)S$/) || string.match(/^(\d+):(\d+):(\d+)$/) $1.to_i * 3600 + $2.to_i * 60 + $3.to_i else nil end end |
#string_to_boolean(value) ⇒ Object
217 218 219 |
# File 'lib/xml_mapper.rb', line 217 def string_to_boolean(value) MAPPINGS[value.to_s.downcase] end |
#value_from_doc_and_mapping(doc, mapping, xml_path = nil) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/xml_mapper.rb', line 161 def value_from_doc_and_mapping(doc, mapping, xml_path = nil) if mapping[:type] == :many mapping[:options][:mapper].attributes_from_xml(doc.send(self.selector_mode, mapping[:xpath]).to_a, xml_path) else node = mapping[:xpath].length == 0 ? doc : doc.xpath(mapping[:xpath]).first if mapping[:type] == :exists !node.nil? elsif mapping[:type] == :not_exists node.nil? else value = case mapping[:type] when :node_name doc.nil? ? nil : doc.name when :inner_text doc.nil? ? nil : doc.inner_text when :node node when :attribute node.nil? ? nil : (node.respond_to?(:root) ? node.root : node)[mapping[:attribute]] else inner_text_for_node(node) end apply_after_map_to_value(value, mapping) end end end |