Skip to content

Commit

Permalink
Merge pull request #13 from wiz-sec/enums
Browse files Browse the repository at this point in the history
Support for enum values
  • Loading branch information
isimluk authored Nov 2, 2020
2 parents c58dedd + ee41cf4 commit 4542678
Show file tree
Hide file tree
Showing 14 changed files with 340 additions and 33 deletions.
2 changes: 1 addition & 1 deletion pkg/template/pkged.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 14 additions & 3 deletions pkg/template/types.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
type {{ .GoName }} struct {
XMLName xml.Name `xml:{{.Name}}`
{{ range .Attributes }}
{{ .GoName }} string `xml:"{{.XmlName}},{{.Modifiers}}"`
{{ .GoName }} {{.GoForeignModule}}{{.GoType}} `xml:"{{.XmlName}},{{.Modifiers}}"`
{{end }}

{{ range .Elements }}
Expand All @@ -33,7 +33,7 @@ import (
{{range .ExportableComplexTypes }}
type {{ .GoName }} struct {
{{ range .Attributes }}
{{ .GoName }} string `xml:"{{.XmlName}},{{.Modifiers}}"`
{{ .GoName }} {{.GoForeignModule}}{{.GoType}} `xml:"{{.XmlName}},{{.Modifiers}}"`
{{end }}

{{ range .Elements }}
Expand All @@ -45,4 +45,15 @@ import (
{{- end}}
InnerXml string `xml:",innerxml"`
}
{{end}}
{{end}}

// XSD SimpleType declarations
{{range .ExportableSimpleTypes }}
type {{ .GoName }} string

{{ $simpleType := . }}
{{ range .Enums }}
const {{ $simpleType.GoName -}} {{- .GoName }} {{ $simpleType.GoName }} = "{{ .XmlName }}"
{{end }}

{{end}}
43 changes: 42 additions & 1 deletion pkg/xsd/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import (
type Attribute struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema attribute"`
Name string `xml:"name,attr"`
Type string `xml:"type,attr"`
Type reference `xml:"type,attr"`
Use string `xml:"use,attr"`
DuplicateCount uint `xml:"-"`
Ref reference `xml:"ref,attr"`
refAttr *Attribute `xml:"-"`
typ Type `xml:"-"`
schema *Schema `xml:"-"`
}

Expand All @@ -31,6 +32,39 @@ func (a *Attribute) GoName() string {
return strcase.ToCamel(name)
}

func (a *Attribute) GoType() string {
if a.typ == nil {
return "string"
}
return a.typ.GoName()
}

func (a *Attribute) isPlainString() bool {
if a.typ == nil {
return true
}
_, ok := a.typ.(staticType)
return ok
}

func (a *Attribute) GoForeignModule() string {
if a.isPlainString() {
return ""
}

foreignSchema := (*Schema)(nil)
if a.refAttr != nil {
foreignSchema = a.refAttr.schema
} else if a.typ != nil {
foreignSchema = a.typ.Schema()
}

if foreignSchema != nil && foreignSchema != a.schema {
return foreignSchema.GoPackageName() + "."
}
return ""
}

func (a *Attribute) Modifiers() string {
res := "attr"
if a.optional() {
Expand Down Expand Up @@ -58,4 +92,11 @@ func (a *Attribute) compile(s *Schema) {
panic("Cannot resolve attribute reference: " + a.Ref)
}
}
if a.Type != "" && a.typ == nil {
a.typ = a.schema.findReferencedType(a.Type)
if a.typ == nil {
panic("Cannot resolve attribute type: " + a.Type)
}

}
}
20 changes: 18 additions & 2 deletions pkg/xsd/attributegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ type AttributeGroup struct {
Name string `xml:"name,attr"`
Ref reference `xml:"ref,attr"`
AttributesDirect []Attribute `xml:"attribute"`
typ Type
schema *Schema `xml:"-"`
typ Type `xml:"-"`
schema *Schema `xml:"-"`
}

func (att *AttributeGroup) Attributes() []Attribute {
Expand All @@ -32,6 +32,22 @@ func (att *AttributeGroup) compile(sch *Schema, parentElement *Element) {
}
att.typ.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 att.Attributes() {
attribute := &att.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
}

}

func (att *AttributeGroup) GoName() string {
Expand Down
3 changes: 3 additions & 0 deletions pkg/xsd/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func (sc *SimpleContent) compile(sch *Schema, parentElement *Element) {
if sc.Extension != nil {
sc.Extension.compile(sch, parentElement)
}
if sc.Restriction != nil {
sc.Restriction.compile(sch, parentElement)
}
}

type ComplexContent struct {
Expand Down
30 changes: 30 additions & 0 deletions pkg/xsd/enum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package xsd

import (
"encoding/xml"
"strings"

"github.com/iancoleman/strcase"
)

// Attribute defines single XML attribute
type Enumeration struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema enumeration"`
Value string `xml:"value,attr"`
}

// Public Go Name of this struct item
func (e *Enumeration) GoName() string {
return strcase.ToCamel(strings.ToLower(e.Value))
}

func (e *Enumeration) Modifiers() string {
return "-"
}

func (e *Enumeration) XmlName() string {
return e.Value
}

func (e *Enumeration) compile(s *Schema) {
}
18 changes: 16 additions & 2 deletions pkg/xsd/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,23 @@ func (ext *Extension) compile(sch *Schema, parentElement *Element) {
ext.typ.compile(sch, parentElement)

for idx, _ := range ext.AttributeGroups {
attrGroup := ext.AttributeGroups[idx]
attrGroup := &ext.AttributeGroups[idx]
attrGroup.compile(sch, parentElement)
ext.AttributeGroups[idx] = attrGroup

}

// 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
}
}
5 changes: 5 additions & 0 deletions pkg/xsd/restriction.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Restriction struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema restriction"`
Base reference `xml:"base,attr"`
AttributesDirect []Attribute `xml:"attribute"`
EnumsDirect []Enumeration `xml:"enumeration"`
SimpleContent *SimpleContent `xml:"simpleContent"`
typ Type
}
Expand Down Expand Up @@ -44,3 +45,7 @@ func (r *Restriction) Attributes() []Attribute {

return result
}

func (r *Restriction) Enums() []Enumeration {
return r.EnumsDirect
}
16 changes: 16 additions & 0 deletions pkg/xsd/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,22 @@ func (sch *Schema) ExportableComplexTypes() []ComplexType {
return res
}

func (sch *Schema) ExportableSimpleTypes() []SimpleType {
elCache := map[string]bool{}
for _, el := range sch.Elements {
elCache[el.GoName()] = true
}

var res []SimpleType
for _, typ := range sch.SimpleTypes {
_, found := elCache[typ.GoName()]
if !found {
res = append(res, typ)
}
}
return res
}

func (sch *Schema) GetAttribute(name string) *Attribute {
for idx, attr := range sch.Attributes {
if attr.Name == name {
Expand Down
46 changes: 31 additions & 15 deletions pkg/xsd/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,20 @@ func (ct *ComplexType) compile(sch *Schema, parentElement *Element) {
}

type SimpleType struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema simpleType"`
Name string `xml:"name,attr"`
schema *Schema `xml:"-"`
XMLName xml.Name `xml:"http://www.w3.org/2001/XMLSchema simpleType"`
Name string `xml:"name,attr"`
Restriction *Restriction `xml:"restriction"`
schema *Schema `xml:"-"`
}

func (st *SimpleType) GoName() string {
return strcase.ToCamel(st.Name)
}

func (st *SimpleType) GoTypeName() string {
if st.Restriction != nil && st.Restriction.typ != nil {
return st.Restriction.typ.GoTypeName()
}
return "string"
}

Expand All @@ -133,7 +137,9 @@ func (st *SimpleType) Schema() *Schema {
}

func (st *SimpleType) compile(sch *Schema, parentElement *Element) {
st.schema = sch
if st.schema == nil {
st.schema = sch
}
}

func (st *SimpleType) Attributes() []Attribute {
Expand All @@ -144,6 +150,13 @@ func (st *SimpleType) Elements() []Element {
return []Element{}
}

func (st *SimpleType) Enums() []Enumeration {
if st.Restriction != nil {
return st.Restriction.Enums()
}
return []Enumeration{}
}

func (st *SimpleType) ContainsText() bool {
return true
}
Expand Down Expand Up @@ -178,17 +191,20 @@ func (st staticType) compile(*Schema, *Element) {
}

var staticTypes = map[string]staticType{
"string": "string",
"dateTime": "string",
"base64Binary": "string",
"normalizedString": "string",
"token": "string",
"NCName": "string",
"anySimpleType": "string",
"int": "int",
"integer": "int64",
"decimal": "float64",
"boolean": "bool",
"string": "string",
"dateTime": "string",
"base64Binary": "string",
"normalizedString": "string",
"token": "string",
"NCName": "string",
"anySimpleType": "string",
"int": "int",
"integer": "int64",
"nonNegativeInteger": "int",
"anyURI": "string",
"decimal": "float64",
"boolean": "bool",
"ID": "string",
}

func StaticType(name string) staticType {
Expand Down
8 changes: 8 additions & 0 deletions tests/smoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func TestSequenceWithinChoice(t *testing.T) {
assert.Equal(t, strings.ReplaceAll(string(expected), "\r\n", "\n"), string(actual))
}

func TestRestriction(t *testing.T) {
xsdPath := "xsd-examples/valid/restriction.xsd"
actual := assertConvertsFine(t, xsdPath)
expected, err := ioutil.ReadFile("xsd-examples/restriction_result.xsd")
require.NoError(t, err)
assert.Equal(t, strings.ReplaceAll(string(expected), "\r\n", "\n"), string(actual))
}

func assertConvertsFine(t *testing.T, xsdPath string) []byte {
dname, err := ioutil.TempDir("", "xsd2go_tests_")
assert.Nil(t, err)
Expand Down
2 changes: 2 additions & 0 deletions tests/xsd-examples/complex_result.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ type MyElementType struct {

InnerXml string `xml:",innerxml"`
}

// XSD SimpleType declarations
Loading

0 comments on commit 4542678

Please # to comment.