Skip to content
14 changes: 14 additions & 0 deletions xsdgen/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type Config struct {
// if populated, only types that are true in this map
// will be selected.
allowTypes map[xml.Name]bool

//True for adding namespace to the struct
addNamespace bool
}

type typeTransform func(xsd.Schema, xsd.Type) xsd.Type
Expand Down Expand Up @@ -76,6 +79,7 @@ var DefaultOptions = []Option{
HandleSOAPArrayType(),
SOAPArrayAsSlice(),
UseFieldNames(),
AddNamespace(false),
}

// The Namespaces option configures the code generation process
Expand Down Expand Up @@ -344,6 +348,15 @@ func useFieldNames(s xsd.Schema, t xsd.Type) xsd.Type {
return t
}

// AddNamespace to the generated structs
func AddNamespace(addNamespace bool) Option {
return func(cfg *Config) Option {
prev := cfg.addNamespace
cfg.addNamespace = addNamespace
return AddNamespace(prev)
}
}

// ProcessTypes allows for users to make arbitrary changes to a type before
// Go source code is generated.
func ProcessTypes(fn func(xsd.Schema, xsd.Type) xsd.Type) Option {
Expand Down Expand Up @@ -409,6 +422,7 @@ func SOAPArrayAsSlice() Option {
}
}


func (cfg *Config) filterFields(t *xsd.ComplexType) ([]xsd.Attribute, []xsd.Element) {
var (
elements []xsd.Element
Expand Down
40 changes: 40 additions & 0 deletions xsdgen/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,43 @@ func ExampleUseFieldNames() {
// }

}

func ExampleAddNamespace() {
doc := xsdfile(`
<complexType name="library">
<sequence>
<element name="book" maxOccurs="1">
<complexType>
<all>
<element name="title" type="xs:string" />
<element name="author" type="xs:string" />
</all>
</complexType>
</element>
</sequence>
</complexType>`)

var cfg xsdgen.Config
cfg.Option(xsdgen.AddNamespace(true))

out, err := cfg.GenSource(doc)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)

// Output: // Code generated by xsdgen.test. DO NOT EDIT.
//
// package ws
//
// type Book struct {
// XMLNs string `xml:"xmlns:tns,attr,omitempty"`
// Title string `xml:"tns:title"`
// Author string `xml:"tns:author"`
// }

// type Library struct {
// XmlNS string `xml:"xmlns:tns,attr,omitempty"`
// Book Book `xml:"tns:book"`
// }
}
68 changes: 55 additions & 13 deletions xsdgen/xsdgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ func (cfg *Config) expandComplexTypes(types []xsd.Type) []xsd.Type {
for _, el := range b.Elements {
if _, ok := shadowedElements[el.Name]; !ok {
elements = append(elements, el)

} else {
cfg.debugf("complexType %s: extended element %s is overrided",
c.Name.Local, el.Name.Local)
Expand Down Expand Up @@ -522,6 +523,17 @@ func (cfg *Config) flatten1(t xsd.Type, push func(xsd.Type), depth int) xsd.Type
panic(fmt.Errorf("unexpected %T(%s %s)", t, xsd.XMLName(t).Space, xsd.XMLName(t).Local))
}

func addNamespace(t *xsd.ComplexType) {
if t.Elements[0].Name.Local != "XMLNs" {
namespace := make([]xsd.Element, 1)
namespace[0].Name.Local = "XMLNs"
namespace[0].Name.Space = t.Elements[0].Name.Space
namespace[0].Type = xsd.String
namespace[0].Scope = t.Elements[0].Scope
t.Elements = append(namespace, t.Elements...)
}
}

func (cfg *Config) genTypeSpec(t xsd.Type) (result []spec, err error) {
var s []spec
cfg.debugf("generating type spec for %q", xsd.XMLName(t).Local)
Expand All @@ -530,6 +542,9 @@ func (cfg *Config) genTypeSpec(t xsd.Type) (result []spec, err error) {
case *xsd.SimpleType:
s, err = cfg.genSimpleType(t)
case *xsd.ComplexType:
if cfg.addNamespace {
addNamespace(t)
}
s, err = cfg.genComplexType(t)
case xsd.Builtin:
// pass
Expand Down Expand Up @@ -684,7 +699,19 @@ func (cfg *Config) genComplexType(t *xsd.ComplexType) ([]spec, error) {
if el.Nillable || el.Optional {
options = ",omitempty"
}

tag := fmt.Sprintf(`xml:"%s %s%s"`, el.Name.Space, el.Name.Local, options)

if cfg.addNamespace {
prefixLocal := strings.Split(el.Scope.Prefix(el.Name), ":")
tag = fmt.Sprintf(`xml:"%s:%s%s"`, prefixLocal[0], el.Name.Local, options)
}

if el.Name.Local == "XMLNs" {
prefixLocal := strings.Split(el.Scope.Prefix(el.Name), ":")
tag = fmt.Sprintf(`xml:"xmlns:%s,attr,omitempty"`, prefixLocal[0])
}

base, err := cfg.expr(el.Type)
if err != nil {
return nil, fmt.Errorf("%s element %s: %v", t.Name.Local, el.Name.Local, err)
Expand Down Expand Up @@ -778,31 +805,44 @@ func (cfg *Config) genComplexType(t *xsd.ComplexType) ([]spec, error) {
xsdType: t,
helperTypes: helperTypes,
}
if len(overrides) > 0 {
if len(overrides) > 0 || cfg.addNamespace {
unmarshal, marshal, err := cfg.genComplexTypeMethods(t, overrides)
if err != nil {
return result, err
} else {
if unmarshal != nil {
s.methods = append(s.methods, unmarshal)
}
if marshal != nil {
s.methods = append(s.methods, marshal)
}
}
if unmarshal != nil {
s.methods = append(s.methods, unmarshal)
}
if marshal != nil {
s.methods = append(s.methods, marshal)
}

}
result = append(result, s)
return result, nil
}

func (cfg *Config) genComplexTypeMethods(t *xsd.ComplexType, overrides []fieldOverride) (marshal, unmarshal *ast.FuncDecl, err error) {
var data struct {
Overrides []fieldOverride
Type string
Overrides []fieldOverride
Type string
NameSpaces []xml.Name
}
data.Overrides = overrides
data.Type = cfg.public(t.Name)

if cfg.addNamespace {
nameSpace := t.Elements[0].Name.Space
for _, el := range t.Elements {
if el.Name.Space != nameSpace {
var namespace xml.Name
namespace.Space = el.Name.Space
namespace.Local = strings.Title(el.Name.Local)
data.NameSpaces = append(data.NameSpaces, namespace)
}
}
}

unmarshal, err = gen.Func("UnmarshalXML").
Receiver("t *"+data.Type).
Args("d *xml.Decoder", "start xml.StartElement").
Expand Down Expand Up @@ -838,9 +878,6 @@ func (cfg *Config) genComplexTypeMethods(t *xsd.ComplexType, overrides []fieldOv
nonDefaultOverrides = append(nonDefaultOverrides, v)
}
}
if len(nonDefaultOverrides) == 0 {
return nil, unmarshal, nil
}

data.Overrides = nonDefaultOverrides
marshal, err = gen.Func("MarshalXML").
Expand All @@ -856,10 +893,15 @@ func (cfg *Config) genComplexTypeMethods(t *xsd.ComplexType, overrides []fieldOv
{{end -}}
}
layout.T = (*T)(t)

{{- range .Overrides}}
layout.{{.FieldName}} = (*{{.ToType}})(&layout.T.{{.FieldName}})
{{end -}}

{{- range .NameSpaces}}
layout.{{.Local}}.XMLNs = "{{.Space}}"
{{end -}}
//
return e.EncodeElement(layout, start)
`, data).Decl()
return marshal, unmarshal, err
Expand Down