Module: XMLUtilities
- Included in:
- VORuby::ADQL::V1_0, VORuby::STC::V1_10::Coords, VORuby::STC::V1_10::Region, VORuby::STC::V1_10::STC, VORuby::STC::V1_30, VORuby::VOEvent::V1_1
- Defined in:
- lib/voruby/misc.rb
Overview
Various utilities for dealing with Ruby classes and XML mappings. Normally included in an existing module.
Instance Method Summary collapse
- #collapse_namespaces(el, existing_namespaces = nil) ⇒ Object
- #current_module ⇒ Object
- #element_from(xml) ⇒ Object
- #element_name_from(klass) ⇒ Object
- #find_class_with_name(name, mod = nil) ⇒ Object
- #find_classes_of_type(type, mod = nil) ⇒ Object
- #find_elements(root, path, ns = nil) ⇒ Object
- #obj_ns(mod_name = nil) ⇒ Object
- #xml_to_obj(node, klass = nil, first_only = false, mod = nil) ⇒ Object
- #xpath_for(type, mod = nil) ⇒ Object
Instance Method Details
#collapse_namespaces(el, existing_namespaces = nil) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/voruby/misc.rb', line 217 def collapse_namespaces(el, existing_namespaces=nil) return if !el or !el.has_elements? existing_namespaces ||= el.namespaces el.children.each do |child| child.namespaces.each do |prefix, uri| child.delete_namespace(prefix) if existing_namespaces.has_key?(prefix) end collapse_namespaces(child, existing_namespaces.merge(child.namespaces)) end end |
#current_module ⇒ Object
136 137 138 139 |
# File 'lib/voruby/misc.rb', line 136 def current_module target = self.is_a?(Class) ? self : self.class target.to_s.split('::')[0..-2].inject(Object){ |x, y| x.const_get(y) } end |
#element_from(xml) ⇒ Object
128 129 130 |
# File 'lib/voruby/misc.rb', line 128 def element_from(xml) xml.is_a?(REXML::Element) ? xml : REXML::Document.new(xml).root end |
#element_name_from(klass) ⇒ Object
132 133 134 |
# File 'lib/voruby/misc.rb', line 132 def element_name_from(klass) klass.respond_to?(:element_name) ? klass.element_name : klass.to_s.split('::').last end |
#find_class_with_name(name, mod = nil) ⇒ Object
149 150 151 152 153 154 155 156 157 |
# File 'lib/voruby/misc.rb', line 149 def find_class_with_name(name, mod=nil) mod ||= current_module mod.const_get( mod.constants.find { |c| obj = mod.const_get(c) obj.is_a?(Class) and name == element_name_from(obj) } ) end |
#find_classes_of_type(type, mod = nil) ⇒ Object
141 142 143 144 145 146 147 |
# File 'lib/voruby/misc.rb', line 141 def find_classes_of_type(type, mod=nil) mod ||= current_module mod.constants.find_all{ |c| obj = mod.const_get(c) obj.is_a?(Class) and obj.allocate().is_a?(type) } end |
#find_elements(root, path, ns = nil) ⇒ Object
173 174 175 176 177 178 |
# File 'lib/voruby/misc.rb', line 173 def find_elements(root, path, ns=nil) ns ||= obj_ns root.children.find_all{ |n| n.respond_to?(:name) and path.include?(n.name) and n.namespace == ns.uri } end |
#obj_ns(mod_name = nil) ⇒ Object
168 169 170 171 |
# File 'lib/voruby/misc.rb', line 168 def obj_ns(mod_name=nil) mod_name ||= current_module.to_s NAMESPACES[mod_name] end |
#xml_to_obj(node, klass = nil, first_only = false, mod = nil) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/voruby/misc.rb', line 180 def xml_to_obj(node, klass=nil, first_only=false, mod=nil) raise 'xml node is required' if !node if klass # style 1 (as in STC): element name + substitution groups determines object mod ||= current_module objects = find_elements(node, xpath_for(klass, mod), obj_ns(mod.to_s)).collect{ |n| find_class_with_name(n.name, mod).from_xml(n) } first_only ? objects.first : objects else # style 2 (as in ADQL): xsi:type determines object # find the xsi:type attribute xsi_type_def = node.attributes.get_attribute_ns(XSI_NAMESPACE.uri, 'type') raise "unable to find xsi:type attribute for #{node}" if !xsi_type_def # extract its namespace prefix (if none is present, use the default) # and the type name. type_def = xsi_type_def.value.split(':') type_ns_prefix = type_def.size == 2 ? type_def.first : nil type_ns_uri = node.namespace(type_ns_prefix) type_name = type_def.size == 2 ? type_def.last : type_def.first # find the module that corresponds to the namespace prefix ns_info = NAMESPACES.find { |key, value| value.uri == type_ns_uri } raise "unable to find module corresponding to #{type_ns_uri}" if !ns_info mod = ns_info.first.to_s.split('::').inject(Object){ |x, y| x.const_get(y) } # search through the module for the class who's xml_type is equal # to the type name klass = mod.constants.find { |c| obj = mod.const_get(c) obj.is_a?(Class) and obj.respond_to?(:xml_type) and obj.respond_to?(:from_xml) and obj.xml_type == type_name }.split('::').inject(Object){ |x, y| x.const_get(y) } raise "unable to find class with an xml_type of #{type_name}" if !klass # instantiate the class klass.from_xml(node) end end |
#xpath_for(type, mod = nil) ⇒ Object
159 160 161 162 163 164 165 166 |
# File 'lib/voruby/misc.rb', line 159 def xpath_for(type, mod=nil) mod ||= current_module find_classes_of_type(type, mod).collect { |klass_name| element_name_from( klass_name.split('::').inject(Object){ |x, y| x.const_get(y) } ) } end |