rxsd 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ # RXSD resolver
2
+ #
3
+ # resolves hanging node relationships and provides overall node access
4
+ #
5
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
6
+ # See COPYING for the License of this software
7
+
8
+ module RXSD
9
+
10
+ # resolves
11
+ class Resolver
12
+
13
+ # return hash of xsd types -> array of type instances for all nodes
14
+ # underneath given node_obj (inclusive)
15
+ def self.node_objects(node_obj, args = {})
16
+ if args.has_key? :node_objs
17
+ node_objs = args[:node_objs]
18
+ else
19
+ node_objs = {XSD::Attribute => [], XSD::AttributeGroup => [], XSD::Choice => [],
20
+ XSD::ComplexContent => [], XSD::ComplexType => [], XSD::Element => [],
21
+ XSD::Extension => [], XSD::Group => [], XSD::List => [], XSD::Restriction => [],
22
+ XSD::Schema => [], XSD::Sequence => [], XSD::SimpleContent => [], XSD::SimpleType => []}
23
+
24
+ unless node_obj.nil?
25
+ node_objs[node_obj.class].push node_obj
26
+ end
27
+ end
28
+
29
+ unless node_obj.nil?
30
+ node_obj.children.each{ |noc|
31
+ unless noc.nil? || node_objs[noc.class].include?(noc)
32
+ node_objs[noc.class].push noc
33
+ node_objs = node_objects(noc, :node_objs => node_objs) # might be better to do a breadth first traversal instead?
34
+ end
35
+ }
36
+ end
37
+
38
+ node_objs
39
+ end
40
+
41
+ # resolves hanging node relationships for specified schema
42
+ def self.resolve_nodes(schema)
43
+ node_objs = node_objects(schema)
44
+ node_objs.each { |xsd_class, nobjs|
45
+ nobjs.each{ |no|
46
+ no.resolve(node_objs)
47
+ }
48
+ }
49
+ end
50
+
51
+ end # class Resolver
52
+ end # module RXSD
@@ -0,0 +1,127 @@
1
+ # RXSD translator
2
+ #
3
+ # transaltes xsd <-> ruby classes & xml <-> instances
4
+ #
5
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
6
+ # See COPYING for the License of this software
7
+
8
+ # include whatever output builders you want here,
9
+ require 'builders/ruby_class'
10
+ require 'builders/ruby_definition'
11
+ require 'builders/ruby_object'
12
+
13
+ module RXSD
14
+
15
+ # Extend XSD Schema Interface to
16
+ # translate xsd/xml to / from ruby classes/objects
17
+ module XSD
18
+ class Schema
19
+
20
+ # helper method, return hash of all tag names -> class builders under schema.
21
+ # An tag is an element or attribute name that can appear in a xml document
22
+ # conforming to the schema
23
+ def tags
24
+ unless defined? @tags
25
+ @tags = {}
26
+ Resolver.
27
+ node_objects(self)[Element].
28
+ find_all { |no| no.class == Element }.
29
+ each { |elem|
30
+ unless elem.name.nil?
31
+ @tags[elem.name] = elem.to_class_builder
32
+ eca = elem.child_attributes
33
+ eca.each { |att|
34
+ @tags[elem.name + ":" + att.name] = att.to_class_builder # prepend element to attribute name to prevent conflicts
35
+ } unless eca.nil?
36
+ end
37
+ }
38
+ end
39
+ return @tags
40
+ end
41
+
42
+ # helper method, return all class builders in/under schema
43
+ def all_class_builders
44
+ to_class_builders.collect { |cb| cb.associated.push cb }.flatten.uniq.compact # FIXME this only filters duplicates by obj id,
45
+ # its possible we have multiple objects refering
46
+ # to the same type, should filter these out here or sometime b4
47
+ end
48
+
49
+ # translates schema and all child entities to instances of specified output type.
50
+ # output_type may be one of
51
+ # * :ruby_classes
52
+ # * :ruby_definitions
53
+ def to(output_type)
54
+ cbs = all_class_builders
55
+ results = []
56
+ cbs.each { |cb|
57
+ # probably a better way to do this at some point than invoking the copy constructors
58
+ #
59
+ # FIXME we create class builders in the translator on the fly, this may cause
60
+ # problems for later operations that need to access class builder attributes which
61
+ # have been created
62
+ case(output_type)
63
+ when :ruby_classes
64
+ cl = RubyClassBuilder.new(:builder => cb).build
65
+ results.push cl unless results.include? cl
66
+ cb.klass = cl # small hack to get around the above fixme... for now
67
+ when :ruby_definitions
68
+ df = RubyDefinitionBuilder.new(:builder => cb).build
69
+ results.push df unless results.include? df
70
+ end
71
+ }
72
+ return results
73
+ end
74
+
75
+ end # class Schema
76
+
77
+ end # module XSD
78
+
79
+ # SchemaInstance contains an array of ObjectBuilders and provides
80
+ # mechanism to instantiate objects from conforming to a xsd schema
81
+ class SchemaInstance
82
+
83
+ # array of object builders represented by current instance
84
+ attr_accessor :object_builders
85
+
86
+ # return array of ObjectBuilders parsed out of a RXSD::XML::Node.
87
+ # Optionally specify parent ObjectBuilder to use
88
+ def self.builders_from_xml(node, parent = nil)
89
+ node_builder = ObjectBuilder.new(:tag_name => node.name, :attributes => node.attrs, :parent => parent)
90
+ parent.children.push node_builder unless parent.nil? || parent.children.include?(node_builder)
91
+ builders = [ node_builder ]
92
+ node.children.each { |c|
93
+ if c.text?
94
+ node_builder.content = c.content if node.children.size == 1 # FIXME if text/children-elements be mixed under a node this wont work
95
+ else
96
+ builders += SchemaInstance.builders_from_xml(c, node_builder )
97
+ end
98
+ }
99
+ return builders
100
+ end
101
+
102
+ # create new schema instance w/ specified args
103
+ def initialize(args = {})
104
+ @object_builders = args[:builders] if args.has_key? :builders
105
+ end
106
+
107
+ # translates SchemaInstance's objects into instances of the specified output type.
108
+ # :output_type may be one of
109
+ # * :ruby_objects
110
+ # Must specify :schema argument containing RXSD::XSD::Schema to use in object creation
111
+ def to(output_type, args = {})
112
+ schema = args[:schema]
113
+ results = []
114
+ @object_builders.each { |ob|
115
+ # probably a better way to do this at some point than invoking the copy constructors
116
+ case(output_type)
117
+ when :ruby_objects
118
+ ob = RubyObjectBuilder.new(:builder => ob).build(schema)
119
+ results.push ob
120
+ end
121
+ }
122
+ return results
123
+ end
124
+
125
+ end
126
+
127
+ end # module RXSD
@@ -0,0 +1,92 @@
1
+ # xml parsing subsystem
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ require 'rubygems'
7
+
8
+ # require libxml adapter
9
+ require 'libxml_adapter'
10
+
11
+ module RXSD
12
+ module XML
13
+
14
+ # RXSD XML node interface subclasses must conform to and helper methods
15
+ class Node
16
+
17
+ # should return name of node, eg <foo> => "foo"
18
+ virtual :name
19
+
20
+ # return hash of attribute name / values
21
+ virtual :attrs
22
+
23
+ # should return bool if node has a parent
24
+ virtual :parent?
25
+
26
+ # should return this nodes's parent, if any
27
+ virtual :parent
28
+
29
+ # should return children nodes
30
+ virtual :children
31
+
32
+ # should return bool if node only contains text
33
+ virtual :text?
34
+
35
+ # should return string contents of text node
36
+ virtual :content
37
+
38
+ # should return list of namespaces corresponding to node
39
+ virtual :namespaces
40
+
41
+ # should also define class method 'xml_root' that returns a node instance corresponding
42
+ # to the root xml node in provided xml data
43
+
44
+ ############################################################################
45
+
46
+ # node factory, returns root node corresponding to specified backend and xml data
47
+ def self.factory(args = {})
48
+ backend = args[:backend]
49
+ xml = args[:xml]
50
+
51
+ # add additional backend drivers here if desired
52
+ return LibXMLNode.xml_root(xml) if backend == :libxml
53
+ return nil
54
+ end
55
+
56
+ # returns root node
57
+ def root
58
+ parent? ? parent.root : self
59
+ end
60
+
61
+ # provides accessor interface to related obj, in our case related xsd obj
62
+ attr_accessor :related
63
+
64
+ # instantiate all children of provided class type
65
+ def children_objs(klass)
66
+ elements = []
67
+ children.find_all { |c| c.name == klass.tag_name }.each { |c|
68
+ elements.push(klass.from_xml(c)) }
69
+ return elements
70
+ end
71
+
72
+ # instantiate first child of provided class type
73
+ def child_obj(klass)
74
+ return children_objs(klass)[0]
75
+ end
76
+
77
+ # return 'value' attribute of all children w/ specified tag
78
+ def child_values(tag_name)
79
+ values = []
80
+ children.find_all { |c| c.name == tag_name }.each { |c| values.push(c.attrs['value']) }
81
+ return values
82
+ end
83
+
84
+ # return 'value' attribute of first childw/ specified tag
85
+ def child_value(tag_name)
86
+ return child_values(tag_name)[0]
87
+ end
88
+
89
+ end
90
+
91
+ end # module XML
92
+ end # module RXSD
@@ -0,0 +1,119 @@
1
+ # The XSD Attribute definition
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ module RXSD
7
+ module XSD
8
+
9
+ # XSD Attribute defintion
10
+ # http://www.w3schools.com/Schema/el_attribute.asp
11
+ class Attribute
12
+
13
+ # attribute attributes
14
+ attr_accessor :id, :name, :use, :form, :default, :fixed, :ref, :type
15
+
16
+ # attribute children
17
+ attr_accessor :simple_type
18
+
19
+ # attribute parent
20
+ attr_accessor :parent
21
+
22
+ # xml tag name
23
+ def self.tag_name
24
+ "attribute"
25
+ end
26
+
27
+ # return xsd node info
28
+ def info
29
+ "attribute id: #{@id} name: #{@name} type: #{@type.class} ref: #{ref.nil? ? "" : ref.name} "
30
+ end
31
+
32
+ # returns array of all children
33
+ def children
34
+ c = []
35
+ c.push @simple_type unless @simple_type.nil?
36
+ return c
37
+ end
38
+
39
+ # node passed in should be a xml node representing the attribute
40
+ def self.from_xml(node)
41
+ attribute = Attribute.new
42
+ attribute.parent = node.parent.related
43
+ node.related = attribute
44
+
45
+ # TODO attribute attributes: | anyAttributes
46
+ attribute.id = node.attrs["id"]
47
+ attribute.name = node.attrs["name"]
48
+ attribute.use = node.attrs["use"]
49
+
50
+ attribute.form = node.attrs.has_key?("form") ?
51
+ node.attrs["form"] : node.parent.attrs["attributeFormDefault"]
52
+
53
+ attribute.default = node.attrs["default"]
54
+ attribute.fixed = node.attrs["fixed"]
55
+
56
+ # FIXME ignoring reference namepsace prefix (if any) for now
57
+ ref = node.attrs["ref"]
58
+ ref = ref.split(':')[1] if !(ref.nil? || ref.index(":").nil?)
59
+ attribute.ref = ref
60
+
61
+ if node.children.find { |c| c.name == SimpleType.tag_name }.nil?
62
+ attribute.type = node.attrs["type"]
63
+ else
64
+ attribute.simple_type = node.child_obj SimpleType
65
+ end
66
+
67
+ return attribute
68
+ end
69
+
70
+ # resolve hanging references given complete xsd node object array
71
+ def resolve(node_objs)
72
+ unless @type.nil?
73
+ builtin = Parser.parse_builtin_type @type
74
+ @type = !builtin.nil? ? builtin : node_objs[SimpleType].find { |no| no.name == @type }
75
+ end
76
+
77
+ unless @ref.nil?
78
+ @ref = node_objs[Attribute].find { |no| no.name == @ref }
79
+ end
80
+ end
81
+
82
+ # convert complex type to class builder
83
+ def to_class_builder
84
+ unless defined? @class_builder
85
+ @class_builder = nil
86
+ if !@ref.nil?
87
+ @class_builder = @ref.to_class_builder
88
+
89
+ elsif !@type.nil?
90
+ if @type.class == SimpleType
91
+ @class_builder = @type.to_class_builder.clone # need to clone here as we're refering to a type that may be used elsewhere
92
+ else
93
+ @class_builder = ClassBuilder.new :klass => @type
94
+ end
95
+
96
+ elsif !@simple_type.nil?
97
+ @class_builder = @simple_type.to_class_builder
98
+
99
+ end
100
+
101
+ unless @class_builder.nil? || @name == "" || @name.nil?
102
+ @class_builder.attribute_name = @name
103
+ @class_builder.klass_name = @name.camelize if @class_builder.klass.nil? && @class_builder.klass_name.nil?
104
+ end
105
+ end
106
+
107
+ return @class_builder
108
+ end
109
+
110
+ # return this attribute (or ref if appropriate) in array
111
+ def child_attributes
112
+ return [@ref] unless @ref.nil?
113
+ return [self]
114
+ end
115
+
116
+ end
117
+
118
+ end # module XSD
119
+ end # module RXSD
@@ -0,0 +1,90 @@
1
+ # The XSD AttributeGroup definition
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ module RXSD
7
+ module XSD
8
+
9
+ # XSD AttributeGroup defintion
10
+ # http://www.w3schools.com/Schema/el_attributegroup.asp
11
+ class AttributeGroup
12
+
13
+ # attribute group attributes
14
+ attr_accessor :id, :name, :ref
15
+
16
+ # attribute group children
17
+ attr_accessor :attributes, :attribute_groups
18
+
19
+ # attribute group parent
20
+ attr_accessor :parent
21
+
22
+ # xml tag name
23
+ def self.tag_name
24
+ "attributeGroup"
25
+ end
26
+
27
+ # return xsd node info
28
+ def info
29
+ "attributeGroup id: #{@id} name: #{@name} ref: #{ref.nil? ? "" : ref.class == String ? ref : ref.name} "
30
+ end
31
+
32
+ # returns array of all children
33
+ def children
34
+ @attributes + @attribute_groups
35
+ end
36
+
37
+ # node passed in should be a xml node representing the attribute group
38
+ def self.from_xml(node)
39
+ attribute_group = AttributeGroup.new
40
+ attribute_group.parent = node.parent.related
41
+ node.related = attribute_group
42
+
43
+ # TODO attribute group attributes: | anyAttributes
44
+ attribute_group.id = node.attrs["id"]
45
+ attribute_group.name = node.attrs["name"]
46
+ attribute_group.ref = node.attrs["ref"]
47
+
48
+ # TODO attribute group children: | anyAttribute
49
+ attribute_group.attributes = node.children_objs Attribute
50
+ attribute_group.attribute_groups = node.children_objs AttributeGroup
51
+
52
+ return attribute_group
53
+ end
54
+
55
+ # resolve hanging references given complete xsd node object array
56
+ def resolve(node_objs)
57
+ unless @ref.nil?
58
+ @ref = node_objs[AttributeGroup].find { |no| no.name == @ref }
59
+ end
60
+ end
61
+
62
+ # convert attribute group to array of class builders
63
+ def to_class_builders
64
+ unless defined? @class_builders
65
+ @class_builders = []
66
+ @attributes.each { |att|
67
+ @class_builders.push att.to_class_builder
68
+ }
69
+ @attribute_groups.each { |atg|
70
+ atg.to_class_builders.each { |atcb|
71
+ @class_builders.push atcb
72
+ }
73
+ }
74
+ end
75
+
76
+ return @class_builders
77
+ end
78
+
79
+ # return all child attributes associated w/ attribute group
80
+ def child_attributes
81
+ atts = []
82
+ @attribute_groups.each { |atg| atts += atg.child_attributes } unless @attribute_groups.nil?
83
+ @attributes.each { |att| atts += att.child_attributes } unless @attributes.nil?
84
+ return atts
85
+ end
86
+
87
+ end
88
+
89
+ end # module XSD
90
+ end # module RXSD