rgen-xsd 0.1.0

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,110 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/../../")
2
+
3
+ require "rgen/environment"
4
+ require "rgen/util/name_helper"
5
+ require 'mmgen/metamodel_generator'
6
+
7
+ require "rgen/xsd/xsd_instantiator"
8
+ require "rgen/xsd/metamodel_modification_helper"
9
+ require 'optparse'
10
+
11
+ include RGen::Util::NameHelper
12
+ include RGen::XSD::MetamodelModificationHelper
13
+
14
+ options = {}
15
+ optparse = OptionParser.new do|opts|
16
+ opts.banner = "Usage: metamodel_generator.rb [options] <schema file>+"
17
+
18
+ opts.on( '--mm VERSION', 'XML schema version: 1.0 or 1.1' ) do |v|
19
+ options[:mm] = v
20
+ end
21
+
22
+ opts.on('-o FILE', "Output metamodel file") do |f|
23
+ options[:outfile] = f
24
+ end
25
+ end
26
+ optparse.parse!
27
+ if !options[:mm]
28
+ puts "Schema version not specified"
29
+ exit
30
+ end
31
+ if !options[:outfile]
32
+ puts "Output file not specified"
33
+ exit
34
+ end
35
+
36
+ case options[:mm]
37
+ when "1.0"
38
+ require "rgen/xsd/1.0/metamodel"
39
+ when "1.1"
40
+ require "rgen/xsd/1.1/metamodel"
41
+ else
42
+ puts "Unknown schema version: #{options[:mm]}"
43
+ exit
44
+ end
45
+ XMLSchemaMetamodel = MM::W3Org2001XMLSchema
46
+
47
+ env = RGen::Environment.new
48
+ mm = XMLSchemaMetamodel
49
+ inst = RGen::XSD::XSDInstantiator.new(env, mm)
50
+
51
+ ARGV.each do |fn|
52
+ inst.instantiate(fn)
53
+ end
54
+
55
+ problems = []
56
+ inst.resolve(problems)
57
+
58
+ if problems.size > 0
59
+ problems.each do |p|
60
+ puts p
61
+ end
62
+ puts "#{problems.size} problems, stop."
63
+ exit
64
+ end
65
+
66
+ require "rgen/xsd/xml_schema_metamodel_ext"
67
+ require "rgen/xsd/xsd_to_ecore"
68
+
69
+ sch = env.find(:class => XMLSchemaMetamodel::Element, :name => "schema").first
70
+
71
+ env_ecore = RGen::Environment.new
72
+ trans = RGen::XSD::XSDToEcoreTransformer.new(env, env_ecore)
73
+ root = trans.transform
74
+
75
+ class_complexType = env_ecore.find(:class => RGen::ECore::EClass, :name => "ComplexType").first
76
+ class_simpleType = env_ecore.find(:class => RGen::ECore::EClass, :name => "SimpleType").first
77
+ class_element = env_ecore.find(:class => RGen::ECore::EClass, :name => "Element").first
78
+ class_group = env_ecore.find(:class => RGen::ECore::EClass, :name => "Group").first
79
+ class_attribute = env_ecore.find(:class => RGen::ECore::EClass, :name => "Attribute").first
80
+ class_attributeGroup = env_ecore.find(:class => RGen::ECore::EClass, :name => "AttributeGroup").first
81
+
82
+ # insert Type class as supertype of ComplexType and SimpleType
83
+ class_type = env_ecore.new(RGen::ECore::EClass, :name => "Type", :ePackage => class_complexType.ePackage,
84
+ :eSuperTypes => class_complexType.eSuperTypes)
85
+ class_complexType.eSuperTypes = [class_type]
86
+ class_simpleType.eSuperTypes = [class_type]
87
+
88
+ # explicit references
89
+ attribute_to_reference(env_ecore, "RestrictionType#base", class_type)
90
+ attribute_to_reference(env_ecore, "RestrictionTYPE#base", class_type)
91
+ attribute_to_reference(env_ecore, "ExtensionType#base", class_type)
92
+ attribute_to_reference(env_ecore, "Element#ref", class_element)
93
+ attribute_to_reference(env_ecore, "Element#type", class_type)
94
+ attribute_to_reference(env_ecore, "Group#ref", class_group)
95
+ attribute_to_reference(env_ecore, "AttributeGroup#ref", class_attributeGroup)
96
+ attribute_to_reference(env_ecore, "Attribute#ref", class_attribute)
97
+ attribute_to_reference(env_ecore, "Attribute#type", class_simpleType)
98
+ attribute_to_reference(env_ecore, "Element#substitutionGroup", class_element)
99
+ attribute_to_reference(env_ecore, "ListTYPE#itemType", class_simpleType)
100
+ attribute_to_reference(env_ecore, "UnionTYPE#memberTypes", class_simpleType)
101
+
102
+ # bidirectional references
103
+ create_opposite(env_ecore, "Element#substitutionGroup", "substitutes", -1)
104
+ create_opposite(env_ecore, "Element#complexType", "containingElement", 1)
105
+ create_opposite(env_ecore, "Element#simpleType", "containingElement", 1)
106
+ create_opposite(env_ecore, "Attribute#simpleType", "containingAttribute", 1)
107
+
108
+ include MMGen::MetamodelGenerator
109
+ generateMetamodel(root, options[:outfile])
110
+
@@ -0,0 +1,41 @@
1
+ module RGen
2
+
3
+ module XSD
4
+
5
+ module MetamodelModificationHelper
6
+
7
+ def find_feature(env, desc)
8
+ env.find(:class => RGen::ECore::EStructuralFeature, :name => desc.split("#").last).
9
+ find{|f| f.eContainingClass.name == desc.split("#").first}
10
+ end
11
+
12
+ def attribute_to_reference(env, desc, target)
13
+ a = find_feature(env, desc)
14
+ r = env.new(RGen::ECore::EReference, Hash[
15
+ RGen::ECore::EStructuralFeature.ecore.eAllStructuralFeatures.collect do |f|
16
+ next if f.derived
17
+ p = [f.name, a.getGeneric(f.name)]
18
+ if f.many
19
+ a.setGeneric(f.name, [])
20
+ else
21
+ a.setGeneric(f.name, nil)
22
+ end
23
+ p
24
+ end])
25
+ r.eType = target
26
+ r
27
+ end
28
+
29
+ def create_opposite(env, desc, name, upper_bound)
30
+ r = find_feature(env, desc)
31
+ r.eOpposite =
32
+ env.new(RGen::ECore::EReference, :name => name, :eType => r.eContainingClass,
33
+ :eContainingClass => r.eType, :upperBound => upper_bound, :eOpposite => r)
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,169 @@
1
+ module RGen
2
+ module XSD
3
+ module Particle
4
+
5
+ # helper structure representing a particle or particle tree
6
+ # particles of kind :choice, :sequence or :all can have child particles
7
+ Particle = Struct.new(:kind, :children, :minOccurs, :maxOccurs, :node)
8
+
9
+ # builds a flat list of the element particles contained in +node+
10
+ # to be used for ComplexType and complex content extensions
11
+ def element_particles(node)
12
+ trees = build_particles_trees(node)
13
+ if trees.size == 1
14
+ flatten_particle_tree(trees.first)
15
+ elsif trees.size > 1
16
+ puts "WARN: only one particle expected as a content model"
17
+ []
18
+ else
19
+ []
20
+ end
21
+ end
22
+
23
+ def add_substitution_particles(particles)
24
+ result = []
25
+ particles.each do |p|
26
+ result << p
27
+ if p.kind == :element
28
+ p.node.substitutes.each do |s|
29
+ result << Particle.new(:element, [], p.minOccurs, p.maxOccurs, s)
30
+ end
31
+ end
32
+ end
33
+ result
34
+ end
35
+
36
+ # flattens the particle tree with root +particle+ and calculates min/max occurrence
37
+ # returns a list of particles of kind "element" and "any"
38
+ # element names are unique throughout the list
39
+ # the order is the order of first occurrence
40
+ def flatten_particle_tree(particle)
41
+ if particle.kind == :element || particle.kind == :any
42
+ [particle]
43
+ else
44
+ eocc = {}
45
+ elist = []
46
+ particle.children.each do |c|
47
+ flatten_particle_tree(c).each do |e|
48
+ if e.kind == :element
49
+ name = e.node.name
50
+ else
51
+ name = "#any#"
52
+ end
53
+ if !eocc[name]
54
+ eocc[name] = []
55
+ elist << name
56
+ end
57
+ eocc[name] << e
58
+ end
59
+ end
60
+ is_unbounded = lambda do |particle, elements|
61
+ (particle.maxOccurs == "unbounded" &&
62
+ elements.any?{|e| e.maxOccurs == "unbounded" || e.maxOccurs.to_i > 0}) ||
63
+ (particle.maxOccurs.to_i > 0 &&
64
+ elements.any?{|e| e.maxOccurs == "unbounded"})
65
+ end
66
+ if particle.kind == :choice
67
+ elist.collect do |n|
68
+ if eocc[n].size < particle.children.size
69
+ # element is not in every choice
70
+ min = 0
71
+ else
72
+ min = eocc[n].collect{|e| e.minOccurs.to_i}.min * particle.minOccurs.to_i
73
+ end
74
+ if is_unbounded.call(particle, eocc[n])
75
+ max = "unbounded"
76
+ else
77
+ max = eocc[n].collect{|e| e.maxOccurs.to_i}.max * particle.maxOccurs.to_i
78
+ end
79
+ if n == "#any#"
80
+ Particle.new(:any, [], min, max, eocc[n].first.node)
81
+ else
82
+ Particle.new(:element, [], min, max, eocc[n].first.node)
83
+ end
84
+ end
85
+ else # sequence or all
86
+ elist.collect do |n|
87
+ min = eocc[n].inject(0){|m, e| m + e.minOccurs.to_i} * particle.minOccurs.to_i
88
+ if is_unbounded.call(particle, eocc[n])
89
+ max = "unbounded"
90
+ else
91
+ max = eocc[n].inject(0){|m, e| m + e.maxOccurs.to_i} * particle.maxOccurs.to_i
92
+ end
93
+ if n == "#any#"
94
+ Particle.new(:any, [], min, max, eocc[n].first.node)
95
+ else
96
+ Particle.new(:element, [], min, max, eocc[n].first.node)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # builds the particle trees for the particles contained in node
104
+ def build_particles_trees(node)
105
+ trees = []
106
+ # ComplexType and extension type have only one choice, sequence, all, group
107
+ choices = node.choice
108
+ choices = [choices].compact unless choices.is_a?(Array)
109
+ choices.each do |c|
110
+ trees << Particle.new(:choice, build_particles_trees(c), c.minOccurs || "1", c.maxOccurs || "1", c)
111
+ end
112
+ sequences = node.sequence
113
+ sequences = [sequences].compact unless sequences.is_a?(Array)
114
+ sequences.each do |s|
115
+ trees << Particle.new(:sequence, build_particles_trees(s), s.minOccurs || "1", s.maxOccurs || "1", s)
116
+ end
117
+ alls = node.all
118
+ alls = [alls].compact unless alls.is_a?(Array)
119
+ alls.each do |a|
120
+ trees << Particle.new(:all, build_particles_trees(s), a.minOccurs || "1", a.maxOccurs || "1", a)
121
+ end
122
+ # Group definitions don't have group reference particles
123
+ if node.respond_to?(:group)
124
+ groups = node.group
125
+ groups = [groups].compact unless groups.is_a?(Array)
126
+ groups.each do |g|
127
+ if g.ref
128
+ # the referenced group is a Model Group Definition, i.e. a node wrapping a Model Group
129
+ # it must contain at most one of Choice, Sequence, All
130
+ # it must not contain another "group" tag because this would be a particle
131
+ group_childs = g.ref.all + g.ref.choice + g.ref.sequence
132
+ if group_childs.size == 1
133
+ gtc = build_particles_trees(g.ref).first
134
+ gtc.minOccurs = g.minOccurs || "1"
135
+ gtc.maxOccurs = g.maxOccurs || "1"
136
+ trees << gtc
137
+ elsif group_childs.size > 1
138
+ puts "WARN: ignoring model group definition containing more than one model group"
139
+ else
140
+ # empty, ignore
141
+ end
142
+ else
143
+ puts "WARN: ignoring non-toplevel group without a ref"
144
+ end
145
+ end
146
+ end
147
+ # ComplexType and complex content extension don't have element particles
148
+ if node.respond_to?(:element)
149
+ node.element.each do |e|
150
+ if e.ref
151
+ trees << Particle.new(:element, [], e.minOccurs || "1", e.maxOccurs || "1", e.ref)
152
+ else
153
+ trees << Particle.new(:element, [], e.minOccurs || "1", e.maxOccurs || "1", e)
154
+ end
155
+ end
156
+ end
157
+ # ComplexType and complex content extension don't have 'any' particles
158
+ if node.respond_to?(:any)
159
+ node.any.each do |a|
160
+ trees << Particle.new(:any, [], a.minOccurs || "1", a.maxOccurs || "1", a)
161
+ end
162
+ end
163
+ trees
164
+ end
165
+
166
+ end
167
+ end
168
+ end
169
+
@@ -0,0 +1,87 @@
1
+ module RGen
2
+ module XSD
3
+ module SimpleType
4
+
5
+ SimpleType = Struct.new(:type, :isList, :minOccurs, :maxOccurs)
6
+
7
+ def build_type_desc(type)
8
+ builtin = builtin_type(type)
9
+ if builtin
10
+ builtin
11
+ elsif type.respond_to?(:list) && type.list
12
+ if type.list.itemType || type.list.simpleType
13
+ td = build_type_desc(type.list.itemType || type.list.simpleType)
14
+ td.isList = true
15
+ td.minOccurs = 0
16
+ td.maxOccurs = -1
17
+ td
18
+ else
19
+ puts "WARN: list type without an item type"
20
+ SimpleType.new(:string, false, 0, 1)
21
+ end
22
+ elsif type.respond_to?(:union) && type.union
23
+ # TODO
24
+ # (type.union.memberTypes + type.union.simpleType).each do |t|
25
+ # build_type_desc(t)
26
+ # end
27
+ # TODO: make this a string instead? otherwise there is a problem serializing with RText (could also be fixed in RText: o.to_s)
28
+ SimpleType.new(:object, false, 0, 1)
29
+ elsif type.respond_to?(:restriction) && type.restriction
30
+ if type.restriction.base
31
+ td = build_type_desc(type.restriction.base)
32
+ if td.type == :string && type.restriction.enumeration.size > 0
33
+ SimpleType.new(
34
+ type.restriction.enumeration.collect { |e| e.value },
35
+ false, 0, 1)
36
+ elsif td.isList
37
+ # assumption: restrictions are properly nested
38
+ # note: this doesn't work correctly in case of lists of lists
39
+ td.minOccurs = type.restriction.minLength.first.value.to_i if type.restriction.minLength.first
40
+ td.maxOccurs = type.restriction.maxLength.first.value.to_i if type.restriction.maxLength.first
41
+ td
42
+ else
43
+ # unhandled restriction, pass the original
44
+ td
45
+ end
46
+ else
47
+ puts "WARN: restriction type without a base type"
48
+ SimpleType.new(:string, false, 0, 1)
49
+ end
50
+ else
51
+ puts "WARN: unknown node type: #{type.class}"
52
+ SimpleType.new(:string, false, 0, 1)
53
+ end
54
+ end
55
+
56
+ def builtin_type(type)
57
+ if type.nil?
58
+ # assumen anySimpleType
59
+ return SimpleType.new(:string, false, 0, 1)
60
+ end
61
+ case type.name
62
+ when "anyType"
63
+ SimpleType.new(:object, false, 0, 1)
64
+ when "anySimpleType", "string", "normalizedString", "token", "language", "Name", "NCName",
65
+ "ID", "IDREF", "ENTITY", "NMTOKEN", "base64Binary", "hexBinary", "anyURI", "QName",
66
+ "NOTATION", "duration", "dateTime", "time", "date", "gYearMonth", "gYear", "gMonthDay",
67
+ "gDay", "gMonth"
68
+ SimpleType.new(:string, false, 0, 1)
69
+ when "IDREFS", "ENTITIES", "NMTOKENS"
70
+ SimpleType.new(:string, true, 0, -1)
71
+ when "float", "double"
72
+ SimpleType.new(:float, false, 0, 1)
73
+ when "decimal", "integer", "nonPositiveInteger", "negativeInteger", "long", "int", "short",
74
+ "byte", "nonNegativeInteger", "unsignedLong", "unsignedInt", "unsignedShort",
75
+ "unsignedByte", "positiveInteger"
76
+ SimpleType.new(:int, false, 0, 1)
77
+ when "boolean"
78
+ SimpleType.new(:boolean, false, 0, 1)
79
+ else
80
+ nil
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,6 @@
1
+ This folder contains the following schema parts as published by the W3C
2
+
3
+ * xml.xsd (http://www.w3.org/2007/08/xml.xsd)
4
+
5
+ Copyright � 2007 World Wide Web Consortium, (Massachusetts Institute of Technology, European Research Consortium for Informatics and Mathematics, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231
6
+
@@ -0,0 +1,145 @@
1
+ <?xml version='1.0'?>
2
+ <xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
3
+
4
+ <xs:annotation>
5
+ <xs:documentation>
6
+ See http://www.w3.org/XML/1998/namespace.html and
7
+ http://www.w3.org/TR/REC-xml for information about this namespace.
8
+
9
+ This schema document describes the XML namespace, in a form
10
+ suitable for import by other schema documents.
11
+
12
+ Note that local names in this namespace are intended to be defined
13
+ only by the World Wide Web Consortium or its subgroups. The
14
+ following names are currently defined in this namespace and should
15
+ not be used with conflicting semantics by any Working Group,
16
+ specification, or document instance:
17
+
18
+ base (as an attribute name): denotes an attribute whose value
19
+ provides a URI to be used as the base for interpreting any
20
+ relative URIs in the scope of the element on which it
21
+ appears; its value is inherited. This name is reserved
22
+ by virtue of its definition in the XML Base specification.
23
+
24
+ id (as an attribute name): denotes an attribute whose value
25
+ should be interpreted as if declared to be of type ID.
26
+ This name is reserved by virtue of its definition in the
27
+ xml:id specification.
28
+
29
+ lang (as an attribute name): denotes an attribute whose value
30
+ is a language code for the natural language of the content of
31
+ any element; its value is inherited. This name is reserved
32
+ by virtue of its definition in the XML specification.
33
+
34
+ space (as an attribute name): denotes an attribute whose
35
+ value is a keyword indicating what whitespace processing
36
+ discipline is intended for the content of the element; its
37
+ value is inherited. This name is reserved by virtue of its
38
+ definition in the XML specification.
39
+
40
+ Father (in any context at all): denotes Jon Bosak, the chair of
41
+ the original XML Working Group. This name is reserved by
42
+ the following decision of the W3C XML Plenary and
43
+ XML Coordination groups:
44
+
45
+ In appreciation for his vision, leadership and dedication
46
+ the W3C XML Plenary on this 10th day of February, 2000
47
+ reserves for Jon Bosak in perpetuity the XML name
48
+ xml:Father
49
+ </xs:documentation>
50
+ </xs:annotation>
51
+
52
+ <xs:annotation>
53
+ <xs:documentation>This schema defines attributes and an attribute group
54
+ suitable for use by
55
+ schemas wishing to allow xml:base, xml:lang, xml:space or xml:id
56
+ attributes on elements they define.
57
+
58
+ To enable this, such a schema must import this schema
59
+ for the XML namespace, e.g. as follows:
60
+ &lt;schema . . .>
61
+ . . .
62
+ &lt;import namespace="http://www.w3.org/XML/1998/namespace"
63
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
64
+
65
+ Subsequently, qualified reference to any of the attributes
66
+ or the group defined below will have the desired effect, e.g.
67
+
68
+ &lt;type . . .>
69
+ . . .
70
+ &lt;attributeGroup ref="xml:specialAttrs"/>
71
+
72
+ will define a type which will schema-validate an instance
73
+ element with any of those attributes</xs:documentation>
74
+ </xs:annotation>
75
+
76
+ <xs:annotation>
77
+ <xs:documentation>In keeping with the XML Schema WG's standard versioning
78
+ policy, this schema document will persist at
79
+ http://www.w3.org/2007/08/xml.xsd.
80
+ At the date of issue it can also be found at
81
+ http://www.w3.org/2001/xml.xsd.
82
+ The schema document at that URI may however change in the future,
83
+ in order to remain compatible with the latest version of XML Schema
84
+ itself, or with the XML namespace itself. In other words, if the XML
85
+ Schema or XML namespaces change, the version of this document at
86
+ http://www.w3.org/2001/xml.xsd will change
87
+ accordingly; the version at
88
+ http://www.w3.org/2007/08/xml.xsd will not change.
89
+ </xs:documentation>
90
+ </xs:annotation>
91
+
92
+ <xs:attribute name="lang">
93
+ <xs:annotation>
94
+ <xs:documentation>Attempting to install the relevant ISO 2- and 3-letter
95
+ codes as the enumerated possible values is probably never
96
+ going to be a realistic possibility. See
97
+ RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry
98
+ at http://www.iana.org/assignments/lang-tag-apps.htm for
99
+ further information.
100
+
101
+ The union allows for the 'un-declaration' of xml:lang with
102
+ the empty string.</xs:documentation>
103
+ </xs:annotation>
104
+ <xs:simpleType>
105
+ <xs:union memberTypes="xs:language">
106
+ <xs:simpleType>
107
+ <xs:restriction base="xs:string">
108
+ <xs:enumeration value=""/>
109
+ </xs:restriction>
110
+ </xs:simpleType>
111
+ </xs:union>
112
+ </xs:simpleType>
113
+ </xs:attribute>
114
+
115
+ <xs:attribute name="space">
116
+ <xs:simpleType>
117
+ <xs:restriction base="xs:NCName">
118
+ <xs:enumeration value="default"/>
119
+ <xs:enumeration value="preserve"/>
120
+ </xs:restriction>
121
+ </xs:simpleType>
122
+ </xs:attribute>
123
+
124
+ <xs:attribute name="base" type="xs:anyURI">
125
+ <xs:annotation>
126
+ <xs:documentation>See http://www.w3.org/TR/xmlbase/ for
127
+ information about this attribute.</xs:documentation>
128
+ </xs:annotation>
129
+ </xs:attribute>
130
+
131
+ <xs:attribute name="id" type="xs:ID">
132
+ <xs:annotation>
133
+ <xs:documentation>See http://www.w3.org/TR/xml-id/ for
134
+ information about this attribute.</xs:documentation>
135
+ </xs:annotation>
136
+ </xs:attribute>
137
+
138
+ <xs:attributeGroup name="specialAttrs">
139
+ <xs:attribute ref="xml:base"/>
140
+ <xs:attribute ref="xml:lang"/>
141
+ <xs:attribute ref="xml:space"/>
142
+ <xs:attribute ref="xml:id"/>
143
+ </xs:attributeGroup>
144
+
145
+ </xs:schema>
@@ -0,0 +1,54 @@
1
+ module XMLSchemaMetamodel
2
+
3
+ module Element::ClassModule
4
+ def effectiveElement
5
+ ref || self
6
+ end
7
+ def effectiveType
8
+ e = effectiveElement
9
+ if e.getType && e.complexType
10
+ puts "WARN: element has both, a type reference and a contained type"
11
+ end
12
+ e.getType || e.complexType || e.simpleType
13
+ end
14
+ end
15
+
16
+ module Attribute::ClassModule
17
+ def effectiveAttribute
18
+ ref || self
19
+ end
20
+ def effectiveType
21
+ e = effectiveAttribute
22
+ if e.getType && e.simpleType
23
+ puts "WARN: attribute has both, a type reference and a contained type"
24
+ end
25
+ e.getType || e.simpleType
26
+ end
27
+ end
28
+
29
+ module ComplexType::ClassModule
30
+ def allAttributes
31
+ attribute + attributeGroup.allAttributes +
32
+ (complexContent.andand.extension.andand.allAttributes || []) +
33
+ (simpleContent.andand.extension.andand.allAttributes || [])
34
+ end
35
+ end
36
+
37
+ module ExtensionType::ClassModule
38
+ def allAttributes
39
+ attribute + attributeGroup.allAttributes
40
+ end
41
+ end
42
+
43
+ module AttributeGroup::ClassModule
44
+ def effectiveAttributeGroup
45
+ ref || self
46
+ end
47
+ def allAttributes
48
+ effectiveAttributeGroup.attribute
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+