完成部分xml格式解析方法
This commit is contained in:
parent
249e749e6c
commit
fe2cdb4f21
30
parser.go
30
parser.go
@ -9,6 +9,7 @@ package simpleRequest
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
@ -17,9 +18,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 通用类型解析器
|
||||||
var bodyEntryParsers = map[string]IBodyEntryParser{
|
var bodyEntryParsers = map[string]IBodyEntryParser{
|
||||||
jsonContentType: new(JsonParser),
|
jsonContentType: new(JsonParser),
|
||||||
formDataType: new(FormDataParser),
|
formDataType: new(FormDataParser),
|
||||||
|
xmlDataType: new(XmlParser),
|
||||||
}
|
}
|
||||||
|
|
||||||
type IBodyEntryParser interface {
|
type IBodyEntryParser interface {
|
||||||
@ -138,3 +141,30 @@ func multipartCommonParse(BodyEntry map[string]any) (reader io.Reader, contentTy
|
|||||||
}
|
}
|
||||||
return body, formWriter.FormDataContentType()
|
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("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
124
simpleRequest.go
124
simpleRequest.go
@ -251,64 +251,90 @@ func (s *SimpleRequest) TRACE(url string) (body []byte, err error) {
|
|||||||
// 这里数据
|
// 这里数据
|
||||||
func (s *SimpleRequest) initBody() {
|
func (s *SimpleRequest) initBody() {
|
||||||
contentTypeData := s.headers.Get(hdrContentTypeKey)
|
contentTypeData := s.headers.Get(hdrContentTypeKey)
|
||||||
switch {
|
if contentTypeData != "" {
|
||||||
case IsJSONType(contentTypeData):
|
switch {
|
||||||
var parser, ok = s.bodyEntryParsers[jsonContentType]
|
case IsJSONType(contentTypeData):
|
||||||
if !ok {
|
var parser, ok = s.bodyEntryParsers[jsonContentType]
|
||||||
parser = new(JsonParser)
|
if !ok {
|
||||||
}
|
parser = new(JsonParser)
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
|
||||||
case strings.Contains(contentTypeData, formDataType):
|
case strings.Contains(contentTypeData, formDataType):
|
||||||
var parser, ok = s.bodyEntryParsers[formDataType]
|
var parser, ok = s.bodyEntryParsers[formDataType]
|
||||||
if !ok {
|
if !ok {
|
||||||
parser = new(FormDataParser)
|
parser = new(FormDataParser)
|
||||||
}
|
}
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
fdParser := parser.(*FormDataParser)
|
fdParser := parser.(*FormDataParser)
|
||||||
s.headers.Set("Content-Type", fdParser.ContentType)
|
s.headers.Set("Content-Type", fdParser.ContentType)
|
||||||
|
|
||||||
case IsXMLType(contentTypeData):
|
case IsXMLType(contentTypeData):
|
||||||
//application/soap+xml ,application/xml
|
//application/soap+xml ,application/xml
|
||||||
var parser, ok = s.bodyEntryParsers[xmlDataType]
|
var parser, ok = s.bodyEntryParsers[xmlDataType]
|
||||||
if !ok {
|
if !ok {
|
||||||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
||||||
s.body = strings.NewReader(data)
|
s.body = strings.NewReader(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
|
||||||
case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType):
|
case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType):
|
||||||
var parser, ok = s.bodyEntryParsers[textPlainType]
|
var parser, ok = s.bodyEntryParsers[textPlainType]
|
||||||
if !ok {
|
if !ok {
|
||||||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
||||||
s.body = strings.NewReader(data)
|
s.body = strings.NewReader(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
|
||||||
case contentTypeData == "" && s.BodyEntryMark == BytesEntryType:
|
case strings.Contains(contentTypeData, "form-urlencoded"):
|
||||||
s.body = bytes.NewReader(s.BodyEntries[BytesEntryType.string()].([]byte))
|
//default header type is "x-www-form-urlencoded"
|
||||||
|
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
||||||
case contentTypeData == "" || strings.Contains(contentTypeData, "form-urlencoded"):
|
if !ok {
|
||||||
//default header type is "x-www-form-urlencoded"
|
tmpData := url.Values{}
|
||||||
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
for k, v := range s.BodyEntries {
|
||||||
if !ok {
|
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{}
|
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))
|
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||||||
}
|
}
|
||||||
s.body = strings.NewReader(tmpData.Encode())
|
s.body = strings.NewReader(tmpData.Encode())
|
||||||
s.Headers().ConentType_formUrlencoded()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
} else {
|
||||||
default:
|
switch s.BodyEntryMark {
|
||||||
//todo Automatically determine the data type
|
case BytesEntryType:
|
||||||
tmpData := url.Values{}
|
s.body = bytes.NewReader(s.BodyEntries[BytesEntryType.string()].([]byte))
|
||||||
for k, v := range tmpData {
|
case StringEntryType:
|
||||||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
86
utils.go
86
utils.go
@ -7,6 +7,11 @@
|
|||||||
|
|
||||||
package simpleRequest
|
package simpleRequest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
func IsJSONType(ct string) bool {
|
func IsJSONType(ct string) bool {
|
||||||
return jsonCheck.MatchString(ct)
|
return jsonCheck.MatchString(ct)
|
||||||
}
|
}
|
||||||
@ -24,3 +29,84 @@ func IsInArray(arr []string, str string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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"`
|
||||||
|
}
|
||||||
|
82
utils_test.go
Normal file
82
utils_test.go
Normal file
@ -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: "<UserInfo>\n<Age>18</Age>\n<isTrueMan>true</isTrueMan>\n<assets></assets>\n<Name>JJXu</Name>\n</UserInfo>",
|
||||||
|
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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user