1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00
Files
stackexchange-dnscontrol/vendor/github.com/philhug/opensrs-go/opensrs/xml.go
Tom Limoncelli 16d0043cce Switch from govendor to go modules. (#587)
Thanks to @BenoitKnecht for leading the way on this.
2020-01-18 14:40:28 -05:00

177 lines
3.4 KiB
Go

package opensrs
import (
"encoding/json"
"encoding/xml"
"errors"
"log"
"reflect"
"strconv"
"strings"
)
type Header struct {
XMLName xml.Name `xml:"header"`
Version string `xml:"version"`
}
type Item struct {
XMLName xml.Name `xml:"item"`
Key string `xml:"key,attr"`
DtArray *DtArray `xml:"dt_array,omitempty"`
DtAssoc *DtAssoc `xml:"dt_assoc,omitempty"`
Value string `xml:",chardata"`
}
func (i *Item) decode() interface{} {
if i.DtAssoc != nil {
return i.DtAssoc.decode()
}
if i.DtArray != nil {
return i.DtArray.decode()
}
return i.Value
}
type DtArray struct {
XMLName xml.Name `xml:"dt_array"`
ItemList []Item `xml:"item,omitempty"`
}
func (d *DtArray) decode() []interface{} {
m := make([]interface{}, 0)
for _, element := range d.ItemList {
m = append(m, element.decode())
}
return m
}
type DtAssoc struct {
XMLName xml.Name `xml:"dt_assoc"`
ItemList []Item `xml:"item,omitempty"`
}
func (d *DtAssoc) decode() Map {
m := make(Map)
for _, element := range d.ItemList {
m[element.Key] = element.decode()
}
return m
}
type DataBlock struct {
XMLName xml.Name `xml:"data_block"`
DtAssoc *DtAssoc `xml:"dt_assoc,omitempty"`
//DtArray DtArray `xml:"dt_array,omitempty"`
}
type Map map[string]interface{}
func (d *DataBlock) decode() Map {
m := make(Map)
if d.DtAssoc != nil {
return d.DtAssoc.decode()
}
return m
}
func encodeItem(key string, value reflect.Value) Item {
item := Item{}
item.Key = key
v := internalEncode(value)
s, ok := v.(string)
if ok {
item.Value = s
}
dtass, ok := v.(DtAssoc)
if ok {
item.DtAssoc = &dtass
}
dtarr, ok := v.(DtArray)
if ok {
item.DtArray = &dtarr
}
return item
}
func internalEncode(v reflect.Value) (p interface{}) {
t := v.Type()
switch t.Kind() {
case reflect.Interface:
return internalEncode(v.Elem())
case reflect.String:
return v.Interface().(string)
case reflect.Struct:
dt := DtAssoc{}
for i := 0; i < t.NumField(); i++ {
key := strings.ToLower(t.Field(i).Name)
value := v.Field(i)
item := encodeItem(key, value)
dt.ItemList = append(dt.ItemList, item)
}
return dt
case reflect.Map: // DtAssoc
dt := DtAssoc{}
for _, k := range v.MapKeys() {
v := v.MapIndex(k)
key := k.String()
item := encodeItem(key, v)
dt.ItemList = append(dt.ItemList, item)
}
return dt
case reflect.Slice: //DtArray
dt := DtArray{}
for i := 0; i < v.Len(); i++ {
key := strconv.Itoa(i)
value := v.Index(i)
item := encodeItem(key, value)
dt.ItemList = append(dt.ItemList, item)
}
return dt
default:
log.Println("FAIL, unknown type", t.Kind())
}
return nil
}
type Body struct {
XMLName xml.Name `xml:"body"`
DataBlock DataBlock `xml:"data_block"`
}
type OPSEnvelope struct {
XMLName xml.Name `xml:"OPS_envelope"`
Header Header `xml:"header"`
Body Body `xml:"body"`
}
func FromXml(b []byte, v interface{}) error {
var q OPSEnvelope
err := xml.Unmarshal(b, &q)
if err != nil {
return err
}
m := q.Body.DataBlock.decode()
jsonString, _ := json.Marshal(m)
return json.Unmarshal(jsonString, &v)
}
func ToXml(v interface{}) (b []byte, err error) {
jsonString, _ := json.Marshal(v)
var m interface{}
json.Unmarshal(jsonString, &m)
q := OPSEnvelope{Header: Header{Version: "0.9"}, Body: Body{}}
dtass, ok := internalEncode(reflect.ValueOf(m)).(DtAssoc)
if ok {
q.Body.DataBlock.DtAssoc = &dtass
} else {
return nil, errors.New("Encoding failed")
}
return xml.MarshalIndent(q, "", " ")
}