Re: [go-nuts] json and lower-case keys

2,176 views
Skip to first unread message

David Symonds

unread,
Nov 30, 2012, 6:15:39 AM11/30/12
to Artem Redkin, golan...@googlegroups.com
On Fri, Nov 30, 2012 at 7:03 PM, Artem Redkin <artem....@gmail.com> wrote:

> I enjoy learning go greatly, but some small idiosyncrasies are just plain
> annoying. Why there is no way to make all keys in json lower-case? Most JSON
> API I've seen (including Google's own) use camel case or lower-case plus
> underscores. You advertise go as "fun", but adding tags to all fields is
> not.

You can use a map[string]interface{} as a JSON source, and then you
can use lower-case fields directly.

x := map[string]interface{}{
"whatever_it_is": 7,
"something_else": "yo",
}

Artem Redkin

unread,
Nov 30, 2012, 6:59:56 AM11/30/12
to golan...@googlegroups.com, Artem Redkin
In that case you lose static type checking. Or am I missing something?

Kevin Gillette

unread,
Nov 30, 2012, 9:16:23 AM11/30/12
to golan...@googlegroups.com
I have rather often desired this as well. By far, most of the JSON I've seen uses javascript-style keys (if there's any intent on easing its use within javascript) or underscore/hyphenated keys; almost none of it used true CamelCase, and I've yet to ever see "meaningful" keys (chosen by a human -- not hashed or otherwise generated) that would produce collisions when normalized to one style or another.

Therefore, it'd be rather useful to add something like an NewEncoderConfig function (and a corresponding NewDecoderConfig) that take flags prescribing a key output style for encoding, that will transform keys (field tags would presumably ignore the transform). Several common styles could be included as transform funcs, also allowing custom funcs to be specified. For decoding, an inverse func could be specified, though there would probably only be need for one -- all of the common styles (or even any semantically-consistent mix of styles in one key) can be consistently transformed to CamelCase -- if this func is nil (default case), the current json decoding behavior would be used. If there are any detected collisions produced by the transform, an error could result.

Jason Del Ponte

unread,
Nov 30, 2012, 12:56:25 PM11/30/12
to golan...@googlegroups.com
The method I use to create json specific field naming in go structures is via the field tags property on a field in a struct.  e.g: MyKeyName string `json:"keyName"` 

Example: http://play.golang.org/p/LVBrzw8WBA

The same process applies for xml and really any other kind you'd like to define. the Json marshal package uses reflection to look up the extra identifiers.  As far as I know there is no method for applying a pattern to all fields, though. http://golang.org/pkg/encoding/json/#Marshal  The same pattern applies for unmarshaling a json object.

cheers
Jason

On Friday, November 30, 2012 12:03:27 AM UTC-8, Artem Redkin wrote:
Hi.

I enjoy learning go greatly, but some small idiosyncrasies are just plain annoying. Why there is no way to make all keys in json lower-case? Most JSON API I've seen (including Google's own) use camel case or lower-case plus underscores. You advertise go as "fun", but adding tags to all fields is not.

Thanks.

Kamil Kisiel

unread,
Nov 30, 2012, 1:33:03 PM11/30/12
to golan...@googlegroups.com
I like that idea, I wonder if it would be possible to implement in a backwards-compatible manner. I suppose it would by having a DefaultEncoderConfig that uses the existing behaviour.

In almost all cases I transform JSON keys that look like "FooBar" to "foo_bar" since that's what the APIs I work with expect, and the ones I write provide. Even for single-word keys it's not possible to shortcut by lowercasing the member names since the JSON package can only work with exported fields.

Bill Thiede

unread,
Nov 30, 2012, 4:14:08 PM11/30/12
to golan...@googlegroups.com
In my extreme laziness, I created this helper function to lowercase struct names,  It does an extra decode/encode, so it is a horrible way to do things, but it works alright for 'fun' code, and is easy to use:

func MapFromStruct(data interface{}) (map[string]string, error) {
    jsonw := bytes.NewBuffer(nil)
    enc := json.NewEncoder(jsonw)
    err := enc.Encode(data)
    if err != nil {
        return nil, err
    }

    jsonr := bytes.NewReader(jsonw.Bytes())
    dec := json.NewDecoder(jsonr)
    kv := map[string]interface{}{}
    err = dec.Decode(&kv)
    if err != nil {
        return nil, err
    }

    result := map[string]string{}
    camelCaseRe := regexp.MustCompile(`[\p{Lu}][\p{Ll}]*`)
    for k, v := range kv {
        words := camelCaseRe.FindAllString(k, -1)
        words[0] = strings.ToLower(words[0])
        lowerK := strings.Join(words, "")
        result[lowerK] = fmt.Sprint(v)
    }

    return result, nil
}

Then where you used to have:

    err := enc.Encode(myStruct)

you can do:

    myMap, err := MapFromStruct(myStruct)
    if err != nil {
        return err
    }
    err := enc.Encode(myMap)

It's not something I would let through on a code review, but handy for hacking.  I agree I'd like to see a better solution that didn't require me repeat every field name again in tags.  

Bill

On Friday, November 30, 2012 12:03:27 AM UTC-8, Artem Redkin wrote:
Hi.

I enjoy learning go greatly, but some small idiosyncrasies are just plain annoying. Why there is no way to make all keys in json lower-case? Most JSON API I've seen (including Google's own) use camel case or lower-case plus underscores. You advertise go as "fun", but adding tags to all fields is not.

Thanks.
Reply all
Reply to author
Forward
0 new messages