2016-12-23 3 views
0

Я новичок в программировании в Go, так извиняюсь, если это что-то очевидное. У меня есть файл с именем JSONfoo.json:Как прочитать одно значение из файла JSON с помощью Go

{"type":"fruit","name":"apple","color":"red"} 

и я пишу Go программа, которая имеет что-то делать, когда «имя» значение в файле формата JSON является «яблоко». Он не нуждается в другой информации из этого файла JSON, поскольку этот файл используется для совершенно другой цели в другой области кода.

Я прочитал документацию об Decode() и Unmarshal() и применил 30 различных веб-страниц, описывающих, как читать весь файл в структурах и т. Д., Но все это кажется чрезвычайно сложным для того, что я хочу сделать, правильный код для реализации первые 2 строки этого псевдокода:

file, _ := os.Open("foo.json") 
name = file["name"] 
if (name == "apple") { 
    do stuff 
} 

таким образом, что я в конечном итоге с Go переменной с именем name, который содержит значение строки apple. Каков правильный способ сделать это в Go?

ответ

2

Самый простой способ сделать то, что вы хотите, чтобы декодировать в структуры ,

При условии, что формат остается похож на {"type":"fruit","name":"apple","color":"red"}

type Name struct { 
    Name string `json:"name"` 
} 

var data []byte 
data, _ = ioutil.ReadFile("foo.json") 

var str Name 
_ = json.Unmarshal(data, &str) 

if str.Name == "apple" { 
    // Do Stuff 
} 

Другой вариант заключается в использовании библиотеки сторонних производителей, таких как gabs или jason.

Gabs:

jsonParsed, err := gabs.ParseJSON(data) 
name, ok := jsonParsed.Path("name").Data().(string) 

Jason:

v, _ := jason.NewObjectFromBytes(data) 
name, _ := v.GetString("name") 

Обновление:

Структура

type Name struct { 
    Name string `json:"name"` 
} 

- json-эквивалент {"name":"foo"}.

Так что unmarshaling не будет работать для следующего json с различными форматами.

[{"name":"foo"}] 

{"bar":{"name":"foo"}} 

PS: Как уже упоминалось, W.K.S. В вашем случае анонимной структуры будет достаточно, поскольку вы не используете эту структуру ни для чего другого.

+1

Вам не нужно явно объявлять «данные». Кроме того, если есть только один вывод (например, 'err' из' json.Unmarshal() '), и вы решите его игнорировать, тогда нет необходимости назначать вывод вообще. –

+0

Спасибо за ответ.Когда вы говорите «При условии, что формат остается похожим на ...» - что может быть примером его диссоциирования и привести к нарушению кода? –

+0

@EdMorton Извините, не было на Рождество. Обновлено. –

1

Одна вещь - это прочитать файл, а другой - прочитать или декодировать json-документ. Я оставляю вам полный пример, который делает оба. Чтобы запустить его, вы должны иметь файл с именем file.json в том же каталоге вашего кода или исполняемого файла:

package main 

import (
    "encoding/json" 
    "io/ioutil" 
    "log" 
    "os" 
) 

func main() { 
    f, err := os.Open("file.json") // file.json has the json content 
    if err != nil { 
     log.Fatal(err) 
    } 

    bb, err := ioutil.ReadAll(f) 
    if err != nil { 
     log.Fatal(err) 
    } 

    doc := make(map[string]interface{}) 
    if err := json.Unmarshal(bb, &doc); err != nil { 
     log.Fatal(err) 
    } 

    if name, contains := doc["name"]; contains { 
     log.Printf("Happy end we have a name: %q\n", name) 
    } else { 
     log.Println("Json document doesn't have a name field.") 
    } 

    log.Printf("full json: %s", string(bb)) 
} 

https://play.golang.org/p/0u04MwwGfn

+0

Спасибо за ответ. Я пытаюсь узнать немного больше о трех разных подходах, предложенных здесь (для декодирования в интерфейсе (http://stackoverflow.com/a/41294843/1745001 и http://stackoverflow.com/a/41295594/ 1745001) или именованной структуры (http://stackoverflow.com/a/41296043/1745001) или структуры Без названия (http://stackoverflow.com/a/41296207/1745001).), А затем я начну тестирование. –

+0

Спасибо за помощь, в конце концов, я пошел с подходом, названным структурой, поскольку это, по-видимому, соглашение в каком-то другом коде для продукта, над которым я работаю. –

1

Я также пытался найти простое решение, такие как $d = json_decode($json, true) в PHP и пришел к выводу, что такого простого способа в Голанге нет. Ниже самое простое решение я мог бы сделать (чеки будут пропущены для ясности):

var f interface{} 
err = json.Unmarshal(file, &f) 

m := f.(map[string]interface{}) 
if (m["name"] == "apple") { 
    // Do something 
} 

где

  • file является массивом байт JSON строки,
  • f интерфейса служит как общий контейнер для неизвестной структуры JSON,
  • m - это карта, возвращаемая type assertion.

Мы можем утверждать, что f является отображением строк, потому что Unmarshal() строит переменную этого типа для любого входа JSON. По крайней мере, я не мог заставить его вернуть что-то другое. Можно определить тип переменной с помощью run-time reflection:

fmt.Printf("Type of f = %s\n", reflect.TypeOf(f)) 

Для f переменной выше, код будет печатать Type of f = map[string]interface {}.

Пример

И это полный код с необходимыми проверками:

package main 

import (
    "fmt" 
    "os" 
    "io/ioutil" 
    "encoding/json" 
) 

func main() { 
    // Read entire file into an array of bytes 
    file, err := ioutil.ReadFile("foo.json") 
    if (err != nil) { 
    fmt.Fprintf(os.Stderr, "Failed read file: %s\n", err) 
    os.Exit(1) 
    } 

    var f interface{} 
    err = json.Unmarshal(file, &f) 
    if (err != nil) { 
    fmt.Fprintf(os.Stderr, "Failed to parse JSON: %s\n", err) 
    os.Exit(1) 
    } 

    // Type-cast `f` to a map by means of type assertion. 
    m := f.(map[string]interface{}) 
    fmt.Printf("Parsed data: %v\n", m) 

    // Now we can check if the parsed data contains 'name' key 
    if (m["name"] == "apple") { 
    fmt.Print("Apple found\n") 
    } 
} 

Выход

Parsed data: map[type:fruit name:apple color:red] 
Apple found 
+0

Спасибо за помощь, в конце концов я пошел с именованным структурным подходом, поскольку это, по-видимому, соглашение в каком-то другом коде для продукта, над которым я работаю. –

1

Правильный способ сделать это - это декодировать в экземпляр анонимной структуры, содержащей только поле, которое вам нужно.

func main() { 
    myStruct := struct{ Name string }{} 
    json.Unmarshal([]byte(`{"type":"fruit","name":"apple","color":"red"}`), &myStruct) 
    fmt.Print(myStruct.Name) 
} 

Playground Link

В качестве альтернативы, Вы можете использовать Jeffails/gabs JSON Parser:

jsonParsed,_ := gabs.ParseJSON([]byte(`{"type":"fruit","name":"apple","color":"red"}`)); 
value, ok = jsonParsed.Path("name").Data().(string) 
+0

Спасибо за ответ. Кажется, у меня есть 3 варианта декодирования: интерфейс (http://stackoverflow.com/a/41294843/1745001 и http://stackoverflow.com/a/41295594/1745001), именованная структура (http: // stackoverflow.com/a/41296043/1745001), или Безымянный (http://stackoverflow.com/a/41296207/1745001). Существуют ли какие-либо плюсы и минусы для любого подхода, выходящего за рамки краткой краткости кодов? –

+0

Я бы сказал, это зависит от ваших требований. Декодирование в интерфейс имеет смысл, когда, скажем, веб-api возвращает другую структуру json в зависимости от параметров запроса, которые он получает. Когда известна структура json, структура имеет больше смысла. Именованная структура предпочтительнее, когда структура json будет непосредственно сопоставляться с объектом в вашем приложении. С другой стороны, когда json не представляет собой сущность, и вам просто нужно прочитать значение нескольких полей (например, в вашем вопросе), будет достаточно анонимной структуры. –

+0

Это имеет смысл, спасибо. Похоже, что неназванная структура будет способом сделать это для моего случая (чтение файла конфигурации, который редко изменяется). Теперь к тестированию ... –