rxsd 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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