forked from GoComply/xsd2go
/
extension.go
123 lines (108 loc) · 3.23 KB
/
extension.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package xsd
import (
"encoding/xml"
)
type Extension struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema extension"`
Base reference `xml:"base,attr"`
AttributesDirect []Attribute `xml:"attribute"`
AttributeGroups []AttributeGroup `xml:"attributeGroup"`
Sequence *Sequence `xml:"sequence"`
typ Type
}
func (ext *Extension) Attributes() []Attribute {
attrs := ext.AttributesDirect
if ext.typ != nil {
attrs = append(attrs, ext.typ.Attributes()...)
attrs = deduplicateAttributes(attrs)
}
for idx := range ext.AttributeGroups {
attrGroup := ext.AttributeGroups[idx]
attrs = append(attrs, attrGroup.Attributes()...)
attrs = deduplicateAttributes(attrs)
}
return attrs
}
func (ext *Extension) Elements() []Element {
elements := []Element{}
if ext.Sequence != nil {
elements = append(elements, ext.Sequence.Elements()...)
}
if ext.typ != nil {
elements = append(elements, ext.typ.Elements()...)
elements = deduplicateElements(elements)
}
attrs := ext.Attributes()
goNames := make(map[string]struct{}, len(elements)+len(attrs))
for _, attr := range attrs {
goNames[attr.GoName()] = struct{}{}
}
final := []Element{}
for _, element := range elements {
if _, found := goNames[element.GoFieldName()]; found {
element.FieldOverride = true
}
goNames[element.GoFieldName()] = struct{}{}
final = append(final, element)
}
return final
}
func deduplicateAttributes(attributes []Attribute) []Attribute {
seen := make(map[string]struct{}, len(attributes))
j := 0
for _, attribute := range attributes {
if _, ok := seen[attribute.GoName()]; ok {
continue
}
seen[attribute.GoName()] = struct{}{}
attributes[j] = attribute
j++
}
return attributes[:j]
}
func deduplicateElements(elements []Element) []Element {
seen := make(map[string]struct{}, len(elements))
j := 0
for _, element := range elements {
if _, ok := seen[element.GoName()]; ok {
continue
}
seen[element.GoName()] = struct{}{}
elements[j] = element
j++
}
return elements[:j]
}
func (ext *Extension) ContainsText() bool {
return ext.Base == "xsd:string" || (ext.typ != nil && ext.typ.ContainsText())
}
func (ext *Extension) compile(sch *Schema, parentElement *Element) {
if ext.Sequence != nil {
ext.Sequence.compile(sch, parentElement)
}
if ext.Base == "" {
panic("Not implemented: xsd:extension/@base empty, cannot extend unknown type")
}
ext.typ = sch.findReferencedType(ext.Base)
if ext.typ == nil {
panic("Cannot build xsd:extension: unknown type: " + string(ext.Base))
}
ext.typ.compile(sch, parentElement)
for idx := range ext.AttributeGroups {
attrGroup := &ext.AttributeGroups[idx]
attrGroup.compile(sch, parentElement)
}
// Handle improbable name clash. Consider XSD defining two attributes on the element:
// "id" and "Id", this would create name clash given the camelization we do.
goNames := map[string]uint{}
for idx := range ext.Attributes() {
attribute := &ext.Attributes()[idx]
attribute.compile(sch)
count := goNames[attribute.GoName()]
count += 1
goNames[attribute.GoName()] = count
attribute.DuplicateCount = count
// Second GoName may be different depending on the DuplicateCount
goNames[attribute.GoName()] = count
}
}