package gosoap import ( "encoding/xml" "fmt" "reflect" ) var tokens []xml.Token // MarshalXML envelope the body and encode to xml func (c Client) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { tokens = []xml.Token{} //start envelope if c.Definitions == nil { return fmt.Errorf("definitions is nil") } startEnvelope() if len(c.HeaderParams) > 0 { startHeader(c.HeaderName, c.Definitions.Types[0].XsdSchema[0].TargetNamespace) recursiveEncode(c.HeaderParams) endHeader(c.HeaderName) } err := startBody(c.Method, c.Definitions.Types[0].XsdSchema[0].TargetNamespace) if err != nil { return err } recursiveEncode(c.Params) //end envelope endBody(c.Method) endEnvelope() for _, t := range tokens { err := e.EncodeToken(t) if err != nil { return err } } return e.Flush() } func recursiveEncode(hm interface{}) { v := reflect.ValueOf(hm) var param Param var ok bool switch v.Kind() { case reflect.Map: for _, key := range v.MapKeys() { t := xml.StartElement{ Name: xml.Name{ Space: "", Local: key.String(), }, } tokens = append(tokens, t) recursiveEncode(v.MapIndex(key).Interface()) tokens = append(tokens, xml.EndElement{Name: t.Name}) } case reflect.Slice: for i := 0; i < v.Len(); i++ { recursiveEncode(v.Index(i).Interface()) } case reflect.String: content := xml.CharData(v.String()) tokens = append(tokens, content) case reflect.Struct: param, ok = v.Interface().(Param) if !ok { break } t := xml.StartElement{ Name: xml.Name{ Space: "", Local: param.Key, }, } tokens = append(tokens, t) recursiveEncode(param.Value) tokens = append(tokens, xml.EndElement{Name: t.Name}) } } func startEnvelope() { e := xml.StartElement{ Name: xml.Name{ Space: "", Local: "soap:Envelope", }, Attr: []xml.Attr{ {Name: xml.Name{Space: "", Local: "xmlns:xsi"}, Value: "http://www.w3.org/2001/XMLSchema-instance"}, {Name: xml.Name{Space: "", Local: "xmlns:xsd"}, Value: "http://www.w3.org/2001/XMLSchema"}, {Name: xml.Name{Space: "", Local: "xmlns:soap"}, Value: "http://schemas.xmlsoap.org/soap/envelope/"}, {Name: xml.Name{Space: "", Local: "soap:encodingStyle"}, Value: "http://www.w3.org/2003/05/soap-encoding"}, }, } tokens = append(tokens, e) } func endEnvelope() { e := xml.EndElement{ Name: xml.Name{ Space: "", Local: "soap:Envelope", }, } tokens = append(tokens, e) } func startHeader(m, n string) { h := xml.StartElement{ Name: xml.Name{ Space: "", Local: "soap:Header", }, } if m == "" || n == "" { tokens = append(tokens, h) return } r := xml.StartElement{ Name: xml.Name{ Space: "", Local: m, }, Attr: []xml.Attr{ {Name: xml.Name{Space: "", Local: "xmlns:m"}, Value: n}, }, } tokens = append(tokens, h, r) return } func endHeader(m string) { h := xml.EndElement{ Name: xml.Name{ Space: "", Local: "soap:Header", }, } if m == "" { tokens = append(tokens, h) return } r := xml.EndElement{ Name: xml.Name{ Space: "", Local: m, }, } tokens = append(tokens, r, h) } // startToken initiate body of the envelope func startBody(m, n string) error { b := xml.StartElement{ Name: xml.Name{ Space: "", Local: "soap:Body", }, } if m == "" || n == "" { return fmt.Errorf("method or namespace is empty") } r := xml.StartElement{ Name: xml.Name{ Space: "", Local: fmt.Sprintf("%s:%s", "m", m), }, Attr: []xml.Attr{ {Name: xml.Name{Space: "", Local: "xmlns:m"}, Value: n}, }, } tokens = append(tokens, b, r) return nil } // endToken close body of the envelope func endBody(m string) { b := xml.EndElement{ Name: xml.Name{ Space: "", Local: "soap:Body", }, } r := xml.EndElement{ Name: xml.Name{ Space: "", Local: fmt.Sprintf("%s:%s", "m", m), }, } tokens = append(tokens, r, b) }