2014-12-11 4 views
1

Так у меня есть JSON файл в формате ...Чтение JSON в GO Струны

[ 
    { 
    "Key":"Value", 
    "Key2":"Value2", 
    "Key3":"Value3" 
    }, 
    { 
    "Foo":"Bar", 
    "Blah":2 
    } 
] 

Я хочу просто прочитать в хэш его части и передать их на запрос HTTP, как в goRequest, потому что goRequest отлично подходит только для JSON, находящегося в String.

package main 
request := gorequest.New() 
resp, body, errs := request.Post("http://example.com"). 
Set("Notes","gorequst is coming!"). 
Send(`{"Foo":"Bar","Blah":2}`). 
End() 

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

Я видел много онлайн об этом, но он всегда, кажется, хочет развязать JSON с Go Structs и сорт, что хорошо, если вы хотите заботиться о том, что на самом деле находится в JSON, но в В моем случае это кажется излишним накладным.

Как бы я мог выполнить что-то подобное? Это кажется довольно простым, но ни одна из существующих библиотек JSON для Go, похоже, не может этого сделать.

Спасибо.

+0

Я не понимаю вопрос – fabrizioM

+0

Может быть, я не понимаю ваш вопрос, но вам не нужно использовать библиотеку JSON, если все, что вы хотите сделать, это пройти вокруг JSON текста. –

+0

Мне нужно, чтобы каждый отдельный хэш был его собственным запросом, поэтому мне нужно получить только каждый отдельный хеш. Файл JSON огромен, и я хочу передать его, потому что загрузка его в память невозможна. –

ответ

3

Возможно, вы ищете json.RawMessage.

Для example:

package main 

import (
    "encoding/json" 
    "fmt" 
    "log" 
) 

func main() { 
    txt := []byte(` 
    [ 
     {"key1" : "value1" }, 
     {"key2" : "value2" } 
    ]`) 
    msg := []json.RawMessage{} 
    err := json.Unmarshal(txt, &msg) 
    if err != nil { 
     log.Fatal(err) 
    } 
    for _, c := range msg { 
     fmt.Printf("%s\n", string(c)) 
    } 
} 

Обратите внимание, что избыточные пробелы в примере разделения пар ключ/значение, является намеренным: вы увидите, что они сохраняются в выходных данных.

В качестве альтернативы, даже если вам не нужна точная структура, вы все равно можете динамически выталкивать ее с помощью переменной interface{}. См. Документ JSON and Go для примера, приведенного ниже, в разделе Generic JSON с интерфейсом {}.

Если мы пытаемся сделать что-то вроде потокового подхода, мы можем попытаться сделать что-то обычай с io.Reader. Парсер JSON предполагает, что вы можете одновременно представлять все в памяти. Это предположение может не уместиться в вашей ситуации, поэтому нам нужно сломать несколько вещей.

Возможно, мы могли бы вручную потреблять байты в io.Reader, пока мы едим ведущие [ характера, а затем неоднократно называют json.Decode на остальной части io.Reader. Что-то вроде this:

package main 

import (
    "bytes" 
    "encoding/json" 
    "fmt" 
    "io" 
    "log" 
) 

func main() { 
    var txt io.Reader = bytes.NewBufferString(` 
    [ 
     {"key1" : "value1" }, 
     {"key2" : "value2" } 
    ]`) 
    buf := make([]byte, 1) 
    for { 
     _, err := txt.Read(buf) 
     if err != nil { 
      log.Fatal(err) 
     } 
     if buf[0] == '[' { 
      break 
     } 
    } 
    for { 
     decoder := json.NewDecoder(txt) 
     msg := json.RawMessage{} 
     err := decoder.Decode(&msg) 
     if err != nil { 
      break 
     } 
     fmt.Printf("I see: %s\n", string(msg)) 

     txt = decoder.Buffered() 
     for { 
      _, err := txt.Read(buf) 
      if err != nil { 
       log.Fatal(err) 
      } 
      if buf[0] == ',' || buf[0] == ']' { 
       break 
      } 
     } 

    } 
} 

Этот код сильно запутано и неочевидным. Я также не думаю, что это хорошая идея. Если вам нужно иметь дело с этим потоковым способом, то JSON, вероятно, не является хорошим форматом сериализации для этого сценария. Если у вас есть контроль над входом, вам следует подумать об изменении его, чтобы он стал более подходящим для потокового подхода: взломам, как то, что мы делаем здесь, плохой запах, что вход находится в неправильной форме.

+0

Спасибо Dyoo, это фантастика! Я могу ввести изменения формата ввода в CSV, что, вероятно, было бы проще для потоковой передачи, но мне пришлось бы брать заголовки и сопоставлять их со значениями каждой строки, поэтому я думаю, что после этого мне придется кодировать некоторый JSON из CSV, чтобы сделать эту работу потоковым способом. Является ли стандартным пакетом CSV это возможным? –

+0

Одна из возможностей: вы можете рассмотреть возможность изменения ввода, чтобы он состоял из последовательности отдельных объектов JSON в последовательности, но не внутри массива, а скорее последовательно размещался последовательно в потоке байтов. Вы заметите, что все хакеры в оригинальном подходе - это просто для того, чтобы иметь дело с искусственной синтаксической структурой, размещенной там из-за того, что она находится в явном массиве. – dyoo

+0

См.: Http://play.golang.org/p/d3Rnf4QP9m в качестве примера. – dyoo

0

Вот что я думал как о решении, это выглядит здорово?

package main 
import (
     "encoding/csv" 
     "fmt" 
     "os" 
    "bytes" 
    "flag" 
    "github.com/parnurzeal/gorequest" 
) 
func process_line(headers []string, line []string) { 
    var comma string = "" 
    var buffer bytes.Buffer 
    buffer.WriteString("[{") 
     for i := range headers { 
      buffer.WriteString(fmt.Sprintf("%s\"%s\":\"%s\"", comma, headers[i], line[i])) 
       comma = "," 
     } 
     fmt.Fprintf(&buffer,"}]\n") 
    request := gorequest.New() 
    resp, body, errs := request.Post("www.something.com"). 
       Set("Content-Type", "application/json"). 
       Set("Accept", "application/json"). 
       Send(buffer.String()).End() 
    if errs == nil { 
     return resp 
    }else{ 
     fmt.Println(errs) 
    } 
} 
func main() { 
    file := flag.String("file", "", "Filename?") 
    flag.Parse() 

    if *file == "" { 
     fmt.Println("No file specified. :-(") 
     os.Exit(1) 
    } 
     csvFile, err := os.Open(*file) 
     if err != nil { 
     fmt.Println(err) 
     } 
     defer csvFile.Close() 
     reader := csv.NewReader(csvFile) 
    var i int = 0 
    var headers []string 
    for { 
     line, err := reader.Read() 
     if err != nil { 
      break 
     } 
     if i == 0 { 
      headers = line 
     }else{ 
      go process_line(headers, line) 
     } 
     if i%100 == 0 { 
      fmt.Printf("%v records processed.\n", i) 
     } 
     i += 1 
    } 
}