// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. // Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj import ( "fmt" "sort" ) const ( Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast) SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding) ) type Map map[string]interface{} // Allocate a Map. func New() Map { m := make(map[string]interface{}, 0) return m } // Cast a Map to map[string]interface{} func (mv Map) Old() map[string]interface{} { return mv } // Return a copy of mv as a newly allocated Map. If the Map only contains string, // numeric, map[string]interface{}, and []interface{} values, then it can be thought // of as a "deep copy." Copying a structure (or structure reference) value is subject // to the noted restrictions. // NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags // then only public fields of the structure are in the new Map - and with // keys that conform to any encoding tag instructions. The structure itself will // be represented as a map[string]interface{} value. func (mv Map) Copy() (Map, error) { // this is the poor-man's deep copy // not efficient, but it works j, jerr := mv.Json() // must handle, we don't know how mv got built if jerr != nil { return nil, jerr } return NewMapJson(j) } // --------------- StringIndent ... from x2j.WriteMap ------------- // Pretty print a Map. func (mv Map) StringIndent(offset ...int) string { return writeMap(map[string]interface{}(mv), true, true, offset...) } // Pretty print a Map without the value type information - just key:value entries. func (mv Map) StringIndentNoTypeInfo(offset ...int) string { return writeMap(map[string]interface{}(mv), false, true, offset...) } // writeMap - dumps the map[string]interface{} for examination. // 'typeInfo' causes value type to be printed. // 'offset' is initial indentation count; typically: Write(m). func writeMap(m interface{}, typeInfo, root bool, offset ...int) string { var indent int if len(offset) == 1 { indent = offset[0] } var s string switch m.(type) { case []interface{}: if typeInfo { s += "[[]interface{}]" } for _, v := range m.([]interface{}) { s += "\n" for i := 0; i < indent; i++ { s += " " } s += writeMap(v, typeInfo, false, indent+1) } case map[string]interface{}: list := make([][2]string, len(m.(map[string]interface{}))) var n int for k, v := range m.(map[string]interface{}) { list[n][0] = k list[n][1] = writeMap(v, typeInfo, false, indent+1) n++ } sort.Sort(mapList(list)) for _, v := range list { if root { root = false } else { s += "\n" } for i := 0; i < indent; i++ { s += " " } s += v[0] + " : " + v[1] } default: if typeInfo { s += fmt.Sprintf("[%T] %+v", m, m) } else { s += fmt.Sprintf("%+v", m) } } return s } // ======================== utility =============== type mapList [][2]string func (ml mapList) Len() int { return len(ml) } func (ml mapList) Swap(i, j int) { ml[i], ml[j] = ml[j], ml[i] } func (ml mapList) Less(i, j int) bool { return ml[i][0] <= ml[j][0] }