123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- // anyxml - marshal an XML document from almost any Go variable
- // Marshal XML from map[string]interface{}, arrays, slices, alpha/numeric, etc.
- //
- // Wraps xml.Marshal with functionality in github.com/clbanning/mxj to create
- // a more genericized XML marshaling capability. Note: unmarshaling the resultant
- // XML may not return the original value, since tag labels may have been injected
- // to create the XML representation of the value.
- //
- // See mxj package documentation for more information. See anyxml_test.go for
- // examples or just try Xml() or XmlIndent().
- /*
- Encode an arbitrary JSON object.
- package main
- import (
- "encoding/json"
- "fmt"
- "github.com/clbanning/anyxml"
- )
- func main() {
- jsondata := []byte(`[
- { "somekey":"somevalue" },
- "string",
- 3.14159265,
- true
- ]`)
- var i interface{}
- err := json.Unmarshal(jsondata, &i)
- if err != nil {
- // do something
- }
- x, err := anyxml.XmlIndent(i, "", " ", "mydoc")
- if err != nil {
- // do something else
- }
- fmt.Println(string(x))
- }
- output:
- <mydoc>
- <somekey>somevalue</somekey>
- <element>string</element>
- <element>3.14159265</element>
- <element>true</element>
- </mydoc>
- */
- package anyxml
- import (
- "encoding/xml"
- "reflect"
- "time"
- )
- // Encode arbitrary value as XML. Note: there are no guarantees.
- func Xml(v interface{}, rootTag ...string) ([]byte, error) {
- if reflect.TypeOf(v).Kind() == reflect.Struct {
- return xml.Marshal(v)
- }
- var err error
- s := new(string)
- p := new(pretty)
- var rt string
- if len(rootTag) == 1 {
- rt = rootTag[0]
- } else {
- rt = DefaultRootTag
- }
- var ss string
- var b []byte
- switch v.(type) {
- case []interface{}:
- ss = "<" + rt + ">"
- for _, vv := range v.([]interface{}) {
- switch vv.(type) {
- case map[string]interface{}:
- m := vv.(map[string]interface{})
- if len(m) == 1 {
- for tag, val := range m {
- err = mapToXmlIndent(false, s, tag, val, p)
- }
- } else {
- err = mapToXmlIndent(false, s, "element", vv, p)
- }
- default:
- err = mapToXmlIndent(false, s, "element", vv, p)
- }
- if err != nil {
- break
- }
- }
- ss += *s + "</" + rt + ">"
- b = []byte(ss)
- case map[string]interface{}:
- b, err = anyxml(v.(map[string]interface{}), rootTag...)
- case []map[string]interface{}:
- for _, vv := range v.([]map[string]interface{}) {
- b, err = anyxml(vv, rootTag...)
- ss += string(b)
- if err != nil {
- break
- }
- }
- b = []byte(ss)
- default:
- err = mapToXmlIndent(false, s, rt, v, p)
- b = []byte(*s)
- }
- return b, err
- }
- // Encode arbitrary value as XML. Note: there are no guarantees.
- func XmlWithDateFormat(dateFormat string, v interface{}, rootTag ...string) ([]byte, error) {
- if reflect.TypeOf(v).Kind() == reflect.Struct {
- return xml.Marshal(v)
- }
- var err error
- s := new(string)
- p := new(pretty)
- var rt string
- if len(rootTag) == 1 {
- rt = rootTag[0]
- } else {
- rt = DefaultRootTag
- }
- var ss string
- var b []byte
- switch v.(type) {
- case []interface{}:
- ss = "<" + rt + ">"
- for _, vv := range v.([]interface{}) {
- switch vv.(type) {
- case map[string]interface{}:
- m := vv.(map[string]interface{})
- if len(m) == 1 {
- for tag, val := range m {
- err = mapToXmlIndentWithDateFormat(dateFormat, false, s, tag, val, p)
- }
- } else {
- err = mapToXmlIndentWithDateFormat(dateFormat, false, s, "element", vv, p)
- }
- default:
- err = mapToXmlIndentWithDateFormat(dateFormat, false, s, "element", vv, p)
- }
- if err != nil {
- break
- }
- }
- ss += *s + "</" + rt + ">"
- b = []byte(ss)
- case map[string]interface{}:
- b, err = anyxmlWithDateFormat(dateFormat, v.(map[string]interface{}), rootTag...)
- case []map[string]interface{}:
- for _, vv := range v.([]map[string]interface{}) {
- b, err = anyxmlWithDateFormat(dateFormat, vv, "element")
- ss += (string(b) + "\n")
- if err != nil {
- break
- }
- }
- b = []byte(ss)
- default:
- err = mapToXmlIndentWithDateFormat(dateFormat, false, s, rt, v, p)
- b = []byte(*s)
- }
- return b, err
- }
- // Encode an arbitrary value as a pretty XML string. Note: there are no guarantees.
- func XmlIndent(v interface{}, prefix, indent string, rootTag ...string) ([]byte, error) {
- if reflect.TypeOf(v).Kind() == reflect.Struct {
- return xml.MarshalIndent(v, prefix, indent)
- }
- var err error
- s := new(string)
- p := new(pretty)
- p.indent = indent
- p.padding = prefix
- var rt string
- if len(rootTag) == 1 {
- rt = rootTag[0]
- } else {
- rt = DefaultRootTag
- }
- var ss string
- var b []byte
- switch v.(type) {
- case []interface{}:
- ss = "<" + rt + ">\n"
- p.Indent()
- for _, vv := range v.([]interface{}) {
- switch vv.(type) {
- case map[string]interface{}:
- m := vv.(map[string]interface{})
- if len(m) == 1 {
- for tag, val := range m {
- err = mapToXmlIndent(true, s, tag, val, p)
- }
- } else {
- p.start = 1 // we're 1 tag in to the doc
- err = mapToXmlIndent(true, s, "element", vv, p)
- *s += "\n"
- }
- case []map[string]interface{}:
- *s += p.padding + "<element>\n" + p.padding
- for _, vvv := range vv.([]map[string]interface{}) {
- err = mapToXmlIndent(true, s, "element", vvv, p)
- *s += "\n"
- if err != nil {
- break
- }
- }
- *s += "</element>\n"
- default:
- p.start = 0
- err = mapToXmlIndent(true, s, "element", vv, p)
- }
- if err != nil {
- break
- }
- }
- ss += *s + "</" + rt + ">"
- b = []byte(ss)
- case map[string]interface{}:
- b, err = anyxmlIndent(v.(map[string]interface{}), prefix, indent, rootTag...)
- case []map[string]interface{}:
- for _, vv := range v.([]map[string]interface{}) {
- b, err = anyxmlIndent(vv, prefix, indent, rootTag...)
- ss += (string(b) + "\n")
- if err != nil {
- break
- }
- }
- b = []byte(ss)
- default:
- err = mapToXmlIndent(true, s, rt, v, p)
- b = []byte(*s)
- }
- return b, err
- }
- // Encode an arbitrary value as a pretty XML string. Note: there are no guarantees.
- func XmlIndentWithDateFormat(dateFormat string, v interface{}, prefix, indent string, rootTag ...string) ([]byte, error) {
- if reflect.TypeOf(v).Kind() == reflect.Struct {
- return xml.MarshalIndent(v, prefix, indent)
- }
- var err error
- s := new(string)
- p := new(pretty)
- p.indent = indent
- p.padding = prefix
- var rt string
- if len(rootTag) == 1 {
- rt = rootTag[0]
- } else {
- rt = DefaultRootTag
- }
- var ss string
- var b []byte
- switch v.(type) {
- case []interface{}:
- ss = "<" + rt + ">\n"
- p.Indent()
- for _, vv := range v.([]interface{}) {
- switch vv.(type) {
- case map[string]interface{}:
- m := vv.(map[string]interface{})
- if len(m) == 1 {
- for tag, val := range m {
- err = mapToXmlIndentWithDateFormat(dateFormat, true, s, tag, val, p)
- }
- } else {
- p.start = 1 // we're 1 tag in to the doc
- err = mapToXmlIndentWithDateFormat(dateFormat, true, s, "element", vv, p)
- *s += "\n"
- }
- default:
- p.start = 0
- err = mapToXmlIndentWithDateFormat(dateFormat, true, s, "element", vv, p)
- }
- if err != nil {
- break
- }
- }
- ss += *s + "</" + rt + ">"
- b = []byte(ss)
- case map[string]interface{}:
- b, err = anyxmlIndentWithDateFormat(dateFormat, v.(map[string]interface{}), prefix, indent, rootTag...)
- case []map[string]interface{}:
- for _, vv := range v.([]map[string]interface{}) {
- b, err = anyxmlIndentWithDateFormat(dateFormat, vv, prefix, indent, rootTag...)
- ss += (string(b) + "\n")
- if err != nil {
- break
- }
- }
- b = []byte(ss)
- default:
- err = mapToXmlIndentWithDateFormat(dateFormat, true, s, rt, v, p)
- b = []byte(*s)
- }
- return b, err
- }
- func Struct2MapWithDateFormat(dateFormat string, obj interface{}) map[string]interface{} {
- t := reflect.TypeOf(obj)
- v := reflect.ValueOf(obj)
- var data = make(map[string]interface{})
- for i := 0; i < t.NumField(); i++ {
- if t.Field(i).Type == reflect.TypeOf(time.Now()) {
- data[t.Field(i).Name] = (v.Field(i).Interface().(time.Time)).Format(dateFormat)
- } else {
- data[t.Field(i).Name] = v.Field(i).Interface()
- }
- }
- return data
- }
|