xml.go raw

   1  package dara
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/xml"
   6  	"fmt"
   7  	"reflect"
   8  	"strings"
   9  
  10  	v2 "github.com/clbanning/mxj/v2"
  11  )
  12  
  13  func ToXML(obj map[string]interface{}) string {
  14  	return mapToXML(obj)
  15  }
  16  
  17  func ParseXml(val string, result interface{}) map[string]interface{} {
  18  	resp := make(map[string]interface{})
  19  
  20  	start := getStartElement([]byte(val))
  21  	if result == nil {
  22  		vm, err := v2.NewMapXml([]byte(val))
  23  		if err != nil {
  24  			return nil
  25  		}
  26  		return vm
  27  	}
  28  	out, err := xmlUnmarshal([]byte(val), result)
  29  	if err != nil {
  30  		return resp
  31  	}
  32  	resp[start] = out
  33  	return resp
  34  }
  35  
  36  func mapToXML(val map[string]interface{}) string {
  37  	res := ""
  38  	for key, value := range val {
  39  		switch value.(type) {
  40  		case []interface{}:
  41  			for _, v := range value.([]interface{}) {
  42  				switch v.(type) {
  43  				case map[string]interface{}:
  44  					res += `<` + key + `>`
  45  					res += mapToXML(v.(map[string]interface{}))
  46  					res += `</` + key + `>`
  47  				default:
  48  					if fmt.Sprintf("%v", v) != `<nil>` {
  49  						res += `<` + key + `>`
  50  						res += fmt.Sprintf("%v", v)
  51  						res += `</` + key + `>`
  52  					}
  53  				}
  54  			}
  55  		case map[string]interface{}:
  56  			res += `<` + key + `>`
  57  			res += mapToXML(value.(map[string]interface{}))
  58  			res += `</` + key + `>`
  59  		default:
  60  			if fmt.Sprintf("%v", value) != `<nil>` {
  61  				res += `<` + key + `>`
  62  				res += fmt.Sprintf("%v", value)
  63  				res += `</` + key + `>`
  64  			}
  65  		}
  66  	}
  67  	return res
  68  }
  69  
  70  func getStartElement(body []byte) string {
  71  	d := xml.NewDecoder(bytes.NewReader(body))
  72  	for {
  73  		tok, err := d.Token()
  74  		if err != nil {
  75  			return ""
  76  		}
  77  		if t, ok := tok.(xml.StartElement); ok {
  78  			return t.Name.Local
  79  		}
  80  	}
  81  }
  82  
  83  func xmlUnmarshal(body []byte, result interface{}) (interface{}, error) {
  84  	start := getStartElement(body)
  85  	dataValue := reflect.ValueOf(result).Elem()
  86  	dataType := dataValue.Type()
  87  	for i := 0; i < dataType.NumField(); i++ {
  88  		field := dataType.Field(i)
  89  		name, containsNameTag := field.Tag.Lookup("xml")
  90  		name = strings.Replace(name, ",omitempty", "", -1)
  91  		if containsNameTag {
  92  			if name == start {
  93  				realType := dataValue.Field(i).Type()
  94  				realValue := reflect.New(realType).Interface()
  95  				err := xml.Unmarshal(body, realValue)
  96  				if err != nil {
  97  					return nil, err
  98  				}
  99  				return realValue, nil
 100  			}
 101  		}
 102  	}
 103  	return nil, nil
 104  }
 105