Для кодировки / json, как я могу изящно обрабатывать вызов API JSON, который содержит апострофы в именах ключей? - PullRequest
0 голосов
/ 31 декабря 2018

Я пишу простую программу Go для использования простого API.Некоторые значения некорректно демаршалируют в моей структуре, и я отследил проблему с неверными именами ключей в возвращенном объекте JSON.

Я могу воспроизвести проблему с помощью этого кода:

jsonStr := `{
    "valid_json": "I'm Valid",
    "invalid'json": "I should be valid, but I'm not"
}`

type result struct {
    Valid   string `json:"valid_json"`
    Invalid string `json:"invalid'json"`
}

var res result
err := json.Unmarshal([]byte(jsonStr), &res)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Valid:   %s\n", res.Valid)
fmt.Printf("Invalid: %s\n", res.Invalid)

Результирующий вывод:

Valid:   I'm Valid
Invalid: 

Мой ожидаемый вывод:

Valid:   I'm Valid
Invalid: I should be valid, but I'm not

Я пробовал такие варианты, как экранирование ' в теге struct, но это либо приводит кошибка или просто игнорируется.Я также изучил альтернативные методы, но вернулся с пустыми руками.

Как правильно решить эту проблему с моей стороны?Было бы лучше раздеть ' перед демаршалингом?Или есть какой-то другой способ, которым я мог бы принять одинарную кавычку?

1 Ответ

0 голосов
/ 31 декабря 2018

Согласно документации для json.Marshal ...

Имя ключа будет использоваться, если это непустая строка, состоящая только из букв Unicode, цифр,и пунктуация ASCII, за исключением кавычек, обратной косой черты и запятой.

Соответствующий код выглядит как isValidTag.Согласно комментарию, "символы кавычек зарезервированы" для будущего использования в синтаксисе тега.

func isValidTag(s string) bool {
    if s == "" {
        return false
    }
    for _, c := range s {
        switch {
        case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
            // Backslash and quote chars are reserved, but
            // otherwise any punctuation chars are allowed
            // in a tag name.
        case !unicode.IsLetter(c) && !unicode.IsDigit(c):
            return false
        }
    }
    return true
}

Вы можете обойти это, используя интерфейс вместо struct.

package main
import (
    "fmt"
    "encoding/json"
    "log"
)
func main() {
    jsonStr := `{
        "valid_json": "I'm Valid",
        "invalid'json": "I should be valid, but I'm not"
    }`

    var res interface{}
    err := json.Unmarshal([]byte(jsonStr), &res)
    if err != nil {
        log.Fatal(err)
    }

    m := res.(map[string]interface{})
    for k, v := range m {
        switch vv := v.(type) {
        case string:
            fmt.Println(k, "is string", vv)
        case float64:
            fmt.Println(k, "is float64", vv)
        case []interface{}:
            fmt.Println(k, "is an array:")
            for i, u := range vv {
                fmt.Println(i, u)
            }
        default:
            fmt.Println(k, "is of a type I don't know how to handle")
        }
    }
}

Подробнее см. "Декодирование произвольных данных" в JSON и Go .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...