0

I am working on adding 'array wildcards' to a Go project on Github called jsonget. Here's an example of what I mean by array wildcards:

 > echo "[{product:'coffee', price:2.10}, {product:'beer', price:3.80}]" | jsonget '*.price'

[2.10, 3.80]

The code for my branch is here

The problem I am running into is with typing, when GetValue encounters a * character, it recurses, calling GetValue on the subexpression, but the type always comes back as a string.

For example, in the test file, I give it this piece of json:

    {
      "inventory": [
          {"name": "mountain bike", "price": 251.0},
          {"name": "red wagon", "price": 90.10},
          {"name": "kinesis advantage", "price": 300.0},
          {"name": "a ticket to Mars", "price": 1200000000.0}
      ]
    }

Then query out inventory[*].price, expecting [251,90.1,300,1.2e+09], but instead getting ["251","90.1","300","1.2e+09"].

I would like to avoid using reflection here, but I don't see another way to do this.

2
  • Posting a snippet of code highlighting the issue would be helpful. Commented May 15, 2013 at 3:57
  • Your library is defined inside the main package - you should fix the structure of your project. Commented May 15, 2013 at 9:40

1 Answer 1

1

I apologise if i've misunderstood your question, but hopefully this helps.

I think that you're either going to have to use reflection or a type switch (http://golang.org/doc/effective_go.html#type_switch , which probably uses reflection behind the scenes, not sure on that).

It shouldn't be too hard to modify your existing valueToString function to include a type switch. Possibly rename it to convertValue or something more generic, and put a type switch in it. If the value is an int, return an int, else return a string.

For example:

func convertValue(value interface{}) (text string, i int, err error) { // Was valueToString
    if value == nil && *printNulls == false {
        return "", nil, nil
    }

    textBytes, err := json.Marshal(value)
    if err != nil {
        return "", nil, err
    }
    switch value := value.(type) {
    default:
        text = string(textBytes)
        text = quotedString.ReplaceAllString(text, "$1")
        return text, nil, nil
    case int:
        i = textBytes
        return nil, i, nil
    }
}

That will hopefully string() everything except the values that the type switch detects as ints, which will be returned as they are.

There's probably a cleaner way of doing it, but it would almost certainly involve a large code refactor. The major downside is that now you need to check if a value is nil before using it.

I'm not sure if there's a way to make a single function able to return one value of various types as I'm pretty sure it would play havoc with type safety. If it is possible, I can only imagine doing it by returning an empty interface in the function definition. Sounds messy.

EDIT: Check out Andrew Gerrand's blog post http://blog.golang.org/2011/01/json-and-go.html , especially the bit near the bottom about decoding generic data. It should help.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.