123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // 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]
- }
|