Module: HappyMapper::ClassMethods
- Defined in:
- lib/happymapper.rb
Instance Method Summary collapse
-
#attribute(name, type, options = {}) ⇒ Object
The xml has the following attributes defined.
-
#attributes ⇒ Array<Attribute>
The elements defined through #attribute.
-
#content(name, type, options = {}) ⇒ Object
The value stored in the text node of the current element.
-
#element(name, type, options = {}) ⇒ Object
An element defined in the XML that is parsed.
- #elements ⇒ Array<Element>
-
#has_many(name, type, options = {}) ⇒ Object
The object has many of these elements in the XML.
-
#has_one(name, type, options = {}) ⇒ Object
The object has one of these elements in the XML.
-
#has_xml_content ⇒ Object
Sets the object to have xml content, this will assign the XML contents that are parsed to the attribute accessor xml_content.
-
#namespace(namespace = nil) ⇒ Object
Specify a namespace if a node and all its children are all namespaced elements.
- #parse(xml, options = {}) ⇒ Object
-
#register_namespace(namespace, ns) ⇒ Object
Register a namespace that is used to persist the object namespace back to XML.
- #tag(new_tag_name) ⇒ Object
-
#tag_name ⇒ String
The name of the tag.
Instance Method Details
#attribute(name, type, options = {}) ⇒ Object
The xml has the following attributes defined.
37 38 39 40 41 42 |
# File 'lib/happymapper.rb', line 37 def attribute(name, type, ={}) attribute = Attribute.new(name, type, ) @attributes[to_s] ||= [] @attributes[to_s] << attribute attr_accessor attribute.method_name.intern end |
#attributes ⇒ Array<Attribute>
The elements defined through #attribute.
50 51 52 |
# File 'lib/happymapper.rb', line 50 def attributes @attributes[to_s] || [] end |
#content(name, type, options = {}) ⇒ Object
The value stored in the text node of the current element.
127 128 129 130 |
# File 'lib/happymapper.rb', line 127 def content(name, type, ={}) @content = TextNode.new(name, type, ) attr_accessor @content.method_name.intern end |
#element(name, type, options = {}) ⇒ Object
An element defined in the XML that is parsed.
93 94 95 96 97 98 |
# File 'lib/happymapper.rb', line 93 def element(name, type, ={}) element = Element.new(name, type, ) @elements[to_s] ||= [] @elements[to_s] << element attr_accessor element.method_name.intern end |
#elements ⇒ Array<Element>
107 108 109 |
# File 'lib/happymapper.rb', line 107 def elements @elements[to_s] || [] end |
#has_many(name, type, options = {}) ⇒ Object
The object has many of these elements in the XML.
167 168 169 |
# File 'lib/happymapper.rb', line 167 def has_many(name, type, ={}) element name, type, {:single => false}.merge() end |
#has_one(name, type, options = {}) ⇒ Object
The object has one of these elements in the XML. If there are multiple, the last one will be set to this value.
153 154 155 |
# File 'lib/happymapper.rb', line 153 def has_one(name, type, ={}) element name, type, {:single => true}.merge() end |
#has_xml_content ⇒ Object
Sets the object to have xml content, this will assign the XML contents that are parsed to the attribute accessor xml_content. The object will respond to the method #xml_content and will return the XML data that it has parsed.
138 139 140 |
# File 'lib/happymapper.rb', line 138 def has_xml_content attr_accessor :xml_content end |
#namespace(namespace = nil) ⇒ Object
Specify a namespace if a node and all its children are all namespaced elements. This is simpler than passing the :namespace option to each defined element.
179 180 181 182 |
# File 'lib/happymapper.rb', line 179 def namespace(namespace = nil) @namespace = namespace if namespace @namespace end |
#parse(xml, options = {}) ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
# File 'lib/happymapper.rb', line 208 def parse(xml, = {}) # create a local copy of the objects namespace value for this parse execution namespace = @namespace # If the XML specified is an Node then we have what we need. if xml.is_a?(Nokogiri::XML::Node) node = xml else # If xml is an XML document select the root node of the document if xml.is_a?(Nokogiri::XML::Document) node = xml.root else # Attempt to parse the xml value with Nokogiri XML as a document # and select the root element xml = Nokogiri::XML(xml) node = xml.root end # if the node name is equal to the tag name then the we are parsing the # root element and that is important to record so that we can apply # the correct xpath on the elements of this document. root = node.name == tag_name end # if any namespaces have been provied then we should capture those and then # merge them with any namespaces found on the xml node and merge all that # with any namespaces that have been registered on the object namespaces = [:namespaces] || {} namespaces = namespaces.merge(xml.collect_namespaces) if xml.respond_to?(:collect_namespaces) namespaces = namespaces.merge(@registered_namespaces) # if a namespace has been provided then set the current namespace to it # or set the default namespace to the one defined under 'xmlns' # or set the default namespace to the namespace that matches 'happymapper's if [:namespace] namespace = [:namespace] elsif namespaces.has_key?("xmlns") namespace ||= DEFAULT_NS namespaces[namespace] = namespaces.delete("xmlns") elsif namespaces.has_key?(DEFAULT_NS) namespace ||= DEFAULT_NS end # from the options grab any nodes present and if none are present then # perform the following to find the nodes for the given class nodes = .fetch(:nodes) do # when at the root use the xpath '/' otherwise use a more gready './/' # unless an xpath has been specified, which should overwrite default # and finally attach the current namespace if one has been defined # xpath = (root ? '/' : './/') xpath = [:xpath].to_s.sub(/([^\/])$/, '\1/') if [:xpath] xpath += "#{namespace}:" if namespace nodes = [] # when finding nodes, do it in this order: # 1. specified tag # 2. name of element # 3. tag_name (derived from class name by default) [[:tag], [:name], tag_name].compact.each do |xpath_ext| begin nodes = node.xpath(xpath + xpath_ext.to_s, namespaces) rescue break end break if nodes && !nodes.empty? end nodes end # If the :limit option has been specified then we are going to slice # our node results by that amount to allow us the ability to deal with # a large result set of data. limit = [:in_groups_of] || nodes.size # If the limit of 0 has been specified then the user obviously wants # none of the nodes that we are serving within this batch of nodes. return [] if limit == 0 collection = [] nodes.each_slice(limit) do |slice| part = slice.map do |n| obj = new attributes.each do |attr| obj.send("#{attr.method_name}=",attr.from_xml_node(n, namespace, namespaces)) end elements.each do |elem| obj.send("#{elem.method_name}=",elem.from_xml_node(n, namespace, namespaces)) end if @content obj.send("#{@content.method_name}=",@content.from_xml_node(n, namespace, namespaces)) end # If the HappyMapper class has the method #xml_value=, # attr_writer :xml_value, or attr_accessor :xml_value then we want to # assign the current xml that we just parsed to the xml_value if obj.respond_to?('xml_value=') n.namespaces.each {|name,path| n[name] = path } obj.xml_value = n.to_xml end # If the HappyMapper class has the method #xml_content=, # attr_write :xml_content, or attr_accessor :xml_content then we want to # assign the child xml that we just parsed to the xml_content if obj.respond_to?('xml_content=') n = n.children if n.respond_to?(:children) obj.xml_content = n.to_xml end # collect the object that we have created obj end # If a block has been provided and the user has requested that the objects # be handled in groups then we should yield the slice of the objects to them # otherwise continue to lump them together if block_given? and [:in_groups_of] yield part else collection += part end end # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354 nodes = nil # If the :single option has been specified or we are at the root element # then we are going to return the first item in the collection. Otherwise # the return response is going to be an entire array of items. if [:single] or root collection.first else collection end end |
#register_namespace(namespace, ns) ⇒ Object
Register a namespace that is used to persist the object namespace back to XML.
71 72 73 |
# File 'lib/happymapper.rb', line 71 def register_namespace(namespace, ns) @registered_namespaces.merge!({namespace => ns}) end |
#tag(new_tag_name) ⇒ Object
187 188 189 |
# File 'lib/happymapper.rb', line 187 def tag(new_tag_name) @tag_name = new_tag_name.to_s unless new_tag_name.nil? || new_tag_name.to_s.empty? end |
#tag_name ⇒ String
The name of the tag
196 197 198 |
# File 'lib/happymapper.rb', line 196 def tag_name @tag_name ||= to_s.split('::')[-1].downcase end |