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.
- data/COPYING +8 -0
- data/LICENSE +165 -0
- data/README +19 -0
- data/bin/rxsd-test.rb +41 -0
- data/lib/rxsd.rb +22 -0
- data/lib/rxsd/builder.rb +159 -0
- data/lib/rxsd/builders/ruby_class.rb +79 -0
- data/lib/rxsd/builders/ruby_definition.rb +54 -0
- data/lib/rxsd/builders/ruby_object.rb +59 -0
- data/lib/rxsd/builtin_types.rb +82 -0
- data/lib/rxsd/common.rb +69 -0
- data/lib/rxsd/exceptions.rb +25 -0
- data/lib/rxsd/libxml_adapter.rb +77 -0
- data/lib/rxsd/loader.rb +33 -0
- data/lib/rxsd/parser.rb +135 -0
- data/lib/rxsd/resolver.rb +52 -0
- data/lib/rxsd/translator.rb +127 -0
- data/lib/rxsd/xml.rb +92 -0
- data/lib/rxsd/xsd/attribute.rb +119 -0
- data/lib/rxsd/xsd/attribute_group.rb +90 -0
- data/lib/rxsd/xsd/choice.rb +109 -0
- data/lib/rxsd/xsd/complex_content.rb +87 -0
- data/lib/rxsd/xsd/complex_type.rb +136 -0
- data/lib/rxsd/xsd/element.rb +162 -0
- data/lib/rxsd/xsd/extension.rb +138 -0
- data/lib/rxsd/xsd/group.rb +100 -0
- data/lib/rxsd/xsd/list.rb +101 -0
- data/lib/rxsd/xsd/restriction.rb +186 -0
- data/lib/rxsd/xsd/schema.rb +114 -0
- data/lib/rxsd/xsd/sequence.rb +108 -0
- data/lib/rxsd/xsd/simple_content.rb +86 -0
- data/lib/rxsd/xsd/simple_type.rb +101 -0
- metadata +106 -0
@@ -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
|
data/lib/rxsd/xml.rb
ADDED
@@ -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
|