require 'rgen/instantiator/nodebased_xml_instantiator' module RGen module Instantiator # A default XML instantiator. # Derive your own instantiator from this class or use it as is. # class DefaultXMLInstantiator < NodebasedXMLInstantiator include Util::NameHelper NamespaceDescriptor = Struct.new(:prefix, :target) class << self def map_tag_ns(from, to, prefix="") tag_ns_map[from] = NamespaceDescriptor.new(prefix, to) end def tag_ns_map # :nodoc: @tag_ns_map ||={} @tag_ns_map end end def initialize(env, default_module, create_mm=false) super(env) @default_module = default_module @create_mm = create_mm end def on_descent(node) obj = new_object(node) @env << obj unless obj.nil? node.object = obj node.attributes.each_pair { |k,v| set_attribute(node, k, v) } end def on_ascent(node) node.children.each { |c| assoc_p2c(node, c) } node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata) set_attribute(node, "chardata", node.chardata) end def class_name(str) saneClassName(str) end def new_object(node) ns_desc = self.class.tag_ns_map[node.namespace] class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag) mod = (ns_desc && ns_desc.target) || @default_module build_on_error(NameError, :build_class, class_name, mod) do mod.const_get(class_name).new end end def build_class(name, mod) mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase)) end def method_name(str) saneMethodName(str) end def assoc_p2c(parent, child) return unless parent.object && child.object method_name = method_name(className(child.object)) build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do parent.object.addGeneric(method_name, child.object) child.object.setGeneric("parent", parent.object) end end def build_p2c_assoc(parent, child, method_name) parent.object.class.has_many(method_name, child.object.class) child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase) end def set_attribute(node, attr, value) return unless node.object build_on_error(NoMethodError, :build_attribute, node, attr, value) do node.object.setGeneric(method_name(attr), value) end end def build_attribute(node, attr, value) node.object.class.has_attr(method_name(attr)) end protected # Helper method for implementing classes. # This method yields the given block. # If the metamodel should be create automatically (see constructor) # rescues +error+ and calls +builder_method+ with +args+, then # yields the block again. def build_on_error(error, builder_method, *args) begin yield rescue error if @create_mm send(builder_method, *args) yield else raise end end end end end end