diff --git a/xsdgen/config.go b/xsdgen/config.go index a2bf601..bfa94f6 100644 --- a/xsdgen/config.go +++ b/xsdgen/config.go @@ -740,11 +740,23 @@ func (cfg *Config) soapArrayToSlice(s spec) spec { if !ok { return s } + var nameField *ast.Field + if len(str.Fields.List) == 2 { + // we can ignore the XMLName field + if ident, ok := str.Fields.List[0].Type.(*ast.Ident); ok && ident.Name == "xml.Name" { + nameField = str.Fields.List[0] + str.Fields.List = str.Fields.List[1:] + } + } if len(str.Fields.List) != 1 { return s } slice, ok := str.Fields.List[0].Type.(*ast.ArrayType) if !ok { + // add back the name field if we removed it in the previous step + if nameField != nil { + str.Fields.List = append([]*ast.Field{nameField}, str.Fields.List...) + } return s } @@ -753,6 +765,10 @@ func (cfg *Config) soapArrayToSlice(s spec) spec { // element in the array with the appropriate type. complex, ok := s.xsdType.(*xsd.ComplexType) if !ok { + // add back the name field if we removed it in the previous step + if nameField != nil { + str.Fields.List = append([]*ast.Field{nameField}, str.Fields.List...) + } return s } @@ -764,6 +780,10 @@ func (cfg *Config) soapArrayToSlice(s spec) spec { } if baseType.Space == "" && baseType.Local == "" { + // add back the name field if we removed it in the previous step + if nameField != nil { + str.Fields.List = append([]*ast.Field{nameField}, str.Fields.List...) + } return s } cfg.debugf("flattening single-element slice struct type %s to []%v", s.name, slice.Elt) @@ -831,6 +851,10 @@ func (cfg *Config) soapArrayToSlice(s spec) spec { unmarshal, err := unmarshalFn.Decl() if err != nil { cfg.logf("error generating UnmarshalXML method of %s: %v", s.name, err) + // add back the name field if we removed it in the previous step + if nameField != nil { + str.Fields.List = append([]*ast.Field{nameField}, str.Fields.List...) + } return s } @@ -856,6 +880,10 @@ func (cfg *Config) soapArrayToSlice(s spec) spec { `, itemType, xmltag.Space, xmltag.Local, baseType.Space, baseType.Local).Decl() if err != nil { cfg.logf("error generating MarshalXML method of %s: %v", s.name, err) + // add back the name field if we removed it in the previous step + if nameField != nil { + str.Fields.List = append([]*ast.Field{nameField}, str.Fields.List...) + } return s } diff --git a/xsdgen/example_test.go b/xsdgen/example_test.go index 3e3e004..a39e98a 100644 --- a/xsdgen/example_test.go +++ b/xsdgen/example_test.go @@ -78,8 +78,11 @@ func ExampleIgnoreAttributes() { // // package ws // + // import "encoding/xml" + // // type ArrayOfString struct { - // Items []string `xml:",any"` + // XMLName xml.Name `xml:"http://www.example.com/ ArrayOfString"` + // Items []string `xml:",any"` // } } @@ -108,9 +111,12 @@ func ExampleIgnoreElements() { // // package ws // + // import "encoding/xml" + // // type Person struct { - // Name string `xml:"http://www.example.com/ name"` - // Deceased bool `xml:"http://schemas.xmlsoap.org/soap/encoding/ deceased"` + // XMLName xml.Name `xml:"http://www.example.com/ Person"` + // Name string `xml:"name"` + // Deceased bool `xml:"http://schemas.xmlsoap.org/soap/encoding/ deceased"` // } } @@ -159,7 +165,10 @@ func ExampleReplace() { // // package ws // + // import "encoding/xml" + // // type StringArray struct { + // XMLName xml.Name `xml:"http://www.example.com/ ArrayOfString"` // Items []string `xml:",any"` // ArrayType string `xml:"arrayType,attr,omitempty"` // } @@ -188,11 +197,14 @@ func ExampleHandleSOAPArrayType() { // // package ws // + // import "encoding/xml" + // // type BoolArray struct { - // Items []bool `xml:",any"` - // Offset string `xml:"offset,attr,omitempty"` - // Id string `xml:"id,attr,omitempty"` - // Href string `xml:"href,attr,omitempty"` + // XMLName xml.Name `xml:"http://www.example.com/ BoolArray"` + // Items []bool `xml:",any"` + // Offset string `xml:"offset,attr,omitempty"` + // Id string `xml:"id,attr,omitempty"` + // Href string `xml:"href,attr,omitempty"` // } } @@ -291,16 +303,17 @@ func ExampleUseFieldNames() { // ) // // type Book struct { - // Title string `xml:"http://www.example.com/ title"` - // Published time.Time `xml:"http://www.example.com/ published"` - // Author string `xml:"http://www.example.com/ author"` + // XMLName xml.Name `xml:"http://www.example.com/ book"` + // Title string `xml:"title"` + // Published time.Time `xml:"published"` + // Author string `xml:"author"` // } // // func (t *Book) MarshalXML(e *xml.Encoder, start xml.StartElement) error { // type T Book // var layout struct { // *T - // Published *xsdDate `xml:"http://www.example.com/ published"` + // Published *xsdDate `xml:"published"` // } // layout.T = (*T)(t) // layout.Published = (*xsdDate)(&layout.T.Published) @@ -310,7 +323,7 @@ func ExampleUseFieldNames() { // type T Book // var overlay struct { // *T - // Published *xsdDate `xml:"http://www.example.com/ published"` + // Published *xsdDate `xml:"published"` // } // overlay.T = (*T)(t) // overlay.Published = (*xsdDate)(&overlay.T.Published) @@ -318,7 +331,8 @@ func ExampleUseFieldNames() { // } // // type Library struct { - // Book []Book `xml:"http://www.example.com/ book"` + // XMLName xml.Name `xml:"http://www.example.com/ library"` + // Book []Book `xml:"book"` // } // // type xsdDate time.Time diff --git a/xsdgen/xsdgen.go b/xsdgen/xsdgen.go index 0604c4d..7cc6211 100644 --- a/xsdgen/xsdgen.go +++ b/xsdgen/xsdgen.go @@ -684,7 +684,13 @@ 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) + var tag string + if t.Name.Space == el.Name.Space { + // No need to repeat the namespace if the parent already has it set + tag = fmt.Sprintf(`xml:"%s%s"`, el.Name.Local, options) + } else { + tag = fmt.Sprintf(`xml:"%s %s%s"`, el.Name.Space, el.Name.Local, options) + } base, err := cfg.expr(el.Type) if err != nil { return nil, fmt.Errorf("%s element %s: %v", t.Name.Local, el.Name.Local, err) @@ -771,6 +777,22 @@ func (cfg *Config) genComplexType(t *xsd.ComplexType) ([]spec, error) { } } expr := gen.Struct(fields...) + + // add XMLName field to struct that will be used by xml.Marshal for setting the element name + var tag string + if t.Name.Space != "" { + tag = fmt.Sprintf(`xml:"%s %s"`, t.Name.Space, t.Name.Local) + } else { + tag = fmt.Sprintf(`xml:"%s"`, t.Name.Local) + } + xmlNameField := &ast.Field{ + Tag: gen.String(tag), + Names: []*ast.Ident{{Name: "XMLName"}}, + Type: &ast.Ident{Name: "xml.Name"}, + } + + expr.Fields.List = append([]*ast.Field{xmlNameField}, expr.Fields.List...) + s := spec{ doc: t.Doc, name: cfg.public(t.Name),