From fe2cdb4f212df4704f82c7aa456ae134d26d79ff Mon Sep 17 00:00:00 2001 From: jjxu <428192774@qq.com> Date: Fri, 17 Nov 2023 17:03:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=83=A8=E5=88=86xml?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E8=A7=A3=E6=9E=90=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser.go | 30 +++++++++++ simpleRequest.go | 130 ++++++++++++++++++++++++++++------------------- utils.go | 86 +++++++++++++++++++++++++++++++ utils_test.go | 82 ++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 52 deletions(-) create mode 100644 utils_test.go diff --git a/parser.go b/parser.go index cc0a54e..cae457d 100644 --- a/parser.go +++ b/parser.go @@ -9,6 +9,7 @@ package simpleRequest import ( "bytes" "encoding/json" + "encoding/xml" "fmt" "io" "mime/multipart" @@ -17,9 +18,11 @@ import ( "strings" ) +// 通用类型解析器 var bodyEntryParsers = map[string]IBodyEntryParser{ jsonContentType: new(JsonParser), formDataType: new(FormDataParser), + xmlDataType: new(XmlParser), } type IBodyEntryParser interface { @@ -138,3 +141,30 @@ func multipartCommonParse(BodyEntry map[string]any) (reader io.Reader, contentTy } return body, formWriter.FormDataContentType() } + +type XmlParser struct{} + +func (f XmlParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) (body io.Reader) { + switch bodyType { + case MapEntryType: + xmlData, err := xml.Marshal(BodyEntry[bodyType.string()]) + if err == nil { + return bytes.NewReader(xmlData) + } else { + return strings.NewReader("") + } + case ModelEntryType: + xmlData, err := xml.Marshal(BodyEntry[bodyType.string()]) + if err == nil { + return bytes.NewReader(xmlData) + } else { + return strings.NewReader("") + } + case StringEntryType: + return strings.NewReader(BodyEntry[StringEntryType.string()].(string)) + case BytesEntryType: + return bytes.NewReader(BodyEntry[BytesEntryType.string()].([]byte)) + default: + return strings.NewReader("") + } +} diff --git a/simpleRequest.go b/simpleRequest.go index 803998c..f369790 100644 --- a/simpleRequest.go +++ b/simpleRequest.go @@ -251,64 +251,90 @@ func (s *SimpleRequest) TRACE(url string) (body []byte, err error) { // 这里数据 func (s *SimpleRequest) initBody() { contentTypeData := s.headers.Get(hdrContentTypeKey) - switch { - case IsJSONType(contentTypeData): - var parser, ok = s.bodyEntryParsers[jsonContentType] - if !ok { - parser = new(JsonParser) - } - s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - - case strings.Contains(contentTypeData, formDataType): - var parser, ok = s.bodyEntryParsers[formDataType] - if !ok { - parser = new(FormDataParser) - } - s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - fdParser := parser.(*FormDataParser) - s.headers.Set("Content-Type", fdParser.ContentType) - - case IsXMLType(contentTypeData): - //application/soap+xml ,application/xml - var parser, ok = s.bodyEntryParsers[xmlDataType] - if !ok { - data, _ := s.BodyEntries[StringEntryType.string()].(string) - s.body = strings.NewReader(data) - return - } - s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - - case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType): - var parser, ok = s.bodyEntryParsers[textPlainType] - if !ok { - data, _ := s.BodyEntries[StringEntryType.string()].(string) - s.body = strings.NewReader(data) - return - } - s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - - case contentTypeData == "" && s.BodyEntryMark == BytesEntryType: - s.body = bytes.NewReader(s.BodyEntries[BytesEntryType.string()].([]byte)) + if contentTypeData != "" { + switch { + case IsJSONType(contentTypeData): + var parser, ok = s.bodyEntryParsers[jsonContentType] + if !ok { + parser = new(JsonParser) + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - case contentTypeData == "" || strings.Contains(contentTypeData, "form-urlencoded"): - //default header type is "x-www-form-urlencoded" - var parser, ok = s.bodyEntryParsers["form-urlencoded"] - if !ok { + case strings.Contains(contentTypeData, formDataType): + var parser, ok = s.bodyEntryParsers[formDataType] + if !ok { + parser = new(FormDataParser) + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) + fdParser := parser.(*FormDataParser) + s.headers.Set("Content-Type", fdParser.ContentType) + + case IsXMLType(contentTypeData): + //application/soap+xml ,application/xml + var parser, ok = s.bodyEntryParsers[xmlDataType] + if !ok { + data, _ := s.BodyEntries[StringEntryType.string()].(string) + s.body = strings.NewReader(data) + return + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) + + case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType): + var parser, ok = s.bodyEntryParsers[textPlainType] + if !ok { + data, _ := s.BodyEntries[StringEntryType.string()].(string) + s.body = strings.NewReader(data) + return + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) + + case strings.Contains(contentTypeData, "form-urlencoded"): + //default header type is "x-www-form-urlencoded" + var parser, ok = s.bodyEntryParsers["form-urlencoded"] + if !ok { + tmpData := url.Values{} + for k, v := range s.BodyEntries { + tmpData.Set(k, fmt.Sprintf("%v", v)) + } + s.body = strings.NewReader(tmpData.Encode()) + s.Headers().ConentType_formUrlencoded() + return + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) + default: + //todo Automatically determine the data type tmpData := url.Values{} - for k, v := range s.BodyEntries { + for k, v := range tmpData { + if strings.HasPrefix(k, FormFilePathKey.string()) { + k = k[len(FormFilePathKey):] + } tmpData.Set(k, fmt.Sprintf("%v", v)) } s.body = strings.NewReader(tmpData.Encode()) - s.Headers().ConentType_formUrlencoded() - return } - s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) - default: - //todo Automatically determine the data type - tmpData := url.Values{} - for k, v := range tmpData { - tmpData.Set(k, fmt.Sprintf("%v", v)) + } else { + switch s.BodyEntryMark { + case BytesEntryType: + s.body = bytes.NewReader(s.BodyEntries[BytesEntryType.string()].([]byte)) + case StringEntryType: + s.body = strings.NewReader(s.BodyEntries[BytesEntryType.string()].(string)) + default: + var parser, ok = s.bodyEntryParsers["form-urlencoded"] + if !ok { + tmpData := url.Values{} + for k, v := range s.BodyEntries { + if strings.HasPrefix(k, FormFilePathKey.string()) { + k = k[len(FormFilePathKey):] + } + tmpData.Set(k, fmt.Sprintf("%v", v)) + } + s.body = strings.NewReader(tmpData.Encode()) + s.Headers().ConentType_formUrlencoded() + return + } + s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries) } - s.body = strings.NewReader(tmpData.Encode()) + } + } diff --git a/utils.go b/utils.go index e8729d0..1b929fa 100644 --- a/utils.go +++ b/utils.go @@ -7,6 +7,11 @@ package simpleRequest +import ( + "encoding/xml" + "fmt" +) + func IsJSONType(ct string) bool { return jsonCheck.MatchString(ct) } @@ -24,3 +29,84 @@ func IsInArray(arr []string, str string) bool { } return false } + +type xmlMapEntry struct { + XMLName xml.Name + Value interface{} `xml:",chardata"` +} + +// func MapToXml(data map[string]any) ([]byte, error) { +// xmlData, err := mapToXML(data) +// if err != nil { +// return nil, err +// } +// return xml.MarshalIndent(xmlData, "", " ") +// } +// +// func mapToXML(m map[string]interface{}) (xmlMap map[string]xmlMapEntry, err error) { +// if len(m) > 1 { +// return nil, errors.New("xml format must have a root name,the map value must like this: map[string]interface{}{\"rootName\":map[string]interface{}{}}") +// } +// xmlMap = make(map[string]xmlMapEntry) +// var rootName string +// for root, data := range m { +// rootName = root +// for k, v := range data.(map[string]interface{}) { +// switch typeV := v.(type) { +// case map[string]interface{}: +// subXmlMap, err := mapToXML(typeV) +// if err != nil { +// return +// } +// +// default: +// entry := xmlMapEntry{XMLName: xml.Name{Local: k}, Value: v} +// xmlMap[k] = entry +// } +// } +// } +// +// xmlData := struct { +// XMLName xml.Name +// Data []xmlMapEntry `xml:",any"` +// }{ +// XMLName: xml.Name{Local: rootName}, +// Data: make([]xmlMapEntry, 0, len(xmlMap)), +// } +// +// for _, v := range xmlMap { +// xmlData.Data = append(xmlData.Data, v) +// } +// +// return xml.MarshalIndent(xmlData, "", " ") +// } + +func mapToXML(m map[string]interface{}) ([]byte, error) { + xmlData := make([]xmlNode, 0) + + for k, v := range m { + node := xmlNode{ + XMLName: xml.Name{Local: k}, + } + + switch value := v.(type) { + case map[string]interface{}: + childXML, err := mapToXML(value) + if err != nil { + return nil, err + } + node.Data = childXML + default: + node.Data = []byte(fmt.Sprintf("%v", v)) + } + + xmlData = append(xmlData, node) + } + + return xml.MarshalIndent(xmlData, "", " ") +} + +type xmlNode struct { + XMLName xml.Name + Data []byte `xml:",innerxml"` +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 0000000..5d90b6a --- /dev/null +++ b/utils_test.go @@ -0,0 +1,82 @@ +// Package simpleRequest ----------------------------- +// @file : utils_test.go +// @author : JJXu +// @contact : wavingbear@163.com +// @time : 2023/11/17 16:37 +// ------------------------------------------- +package simpleRequest + +import ( + "fmt" + "testing" +) + +func Test_mapToXML(t *testing.T) { + type args struct { + m map[string]interface{} + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "多级xml测试", + args: args{ + m: map[string]interface{}{ + "UserInfo": map[string]any{ + "Name": "JJXu", + "Age": 18, + "isTrueMan": true, + "assets": map[string]any{ + "car": "BMW", + "house": "shanghai", + }, + }, + }, + }, + want: "\n18\ntrue\n\nJJXu\n", + wantErr: false, + }, + { + name: "错误格式测试", + args: args{}, + want: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := mapToXML(tt.args.m) + if (err != nil) != tt.wantErr { + t.Errorf("mapToXML() error = %v, wantErr %v", err, tt.wantErr) + return + } + if string(got) != tt.want { + t.Errorf("mapToXML() got = %v, want %v", string(got), tt.want) + } + }) + } +} +func Test_mapToXML2(t *testing.T) { + person := map[string]interface{}{ + "userInfo": map[string]interface{}{ + "name": "John", + "age": 30, + "address": map[string]interface{}{ + "street": "123 Main St", + "city": "New York", + }, + }, + } + + xmlBytes, err := mapToXML(person) + if err != nil { + fmt.Println("Error:", err) + return + } + + xmlString := string(xmlBytes) + fmt.Println(xmlString) +}