2014-07-10 5 views
1

저는 최근에 GO로 게임을 시작했으며 http://www.oref.org.il/WarningMessages/alerts.json에서 JSON 응답을 마샬링 해제하려고합니다.
언 마샬링이 실패했다는 것을 이해할 수없는 몇 가지 이유 때문에 언 마샬 된 구조체가 비어 있습니다 (내 생각에 어떻게 든 엔코딩과 관련이있다).json http 응답의 마샬링 해제

아래 코드는 어떤 도움을 주시면 감사하겠습니다.

감사합니다, Itay

package main 

import (
    "fmt" 
    "io/ioutil" 
    "net/http" 
    "encoding/json" 
) 

const alertsUrl = "http://www.oref.org.il/WarningMessages/alerts.json" 

type Record struct { 
    Id string `json:id` 
    Title string `json:title` 
    Data []string `json:data` 
} 

func main() { 
    client := &http.Client{} 
    req, err := http.NewRequest("GET", alertsUrl, nil) 
    perror(err) 

    req.Header.Add("Content-Type", "application/json; charset=utf-8") 
    res, err := client.Do(req) 
    perror(err) 

    defer res.Body.Close() 
    body, err := ioutil.ReadAll(res.Body) 
    perror(err) 

    var record Record 
    json.Unmarshal(body, &record) 
    fmt.Println(record) 
} 

func perror(err error) { 
    if err != nil { 
    panic(err) 
    } 
} 
+0

** 오류를 무시 ** 중지 지금 여기에 질문을하기 전에 모든 오류를 확인하십시오. – Wessie

+0

@Wessie 무시한 오류를 알려주시겠습니까? –

+0

아 ... 글쎄, 나는 잘 모르겠다. 다시 확인하면 Unmarshal 메서드의 서명에 오류가 반환 된 것을 볼 수 있습니다. 나는이 길을 걸을거야. –

답변

3

당신은 JSON Unmarshal에 오류를 무시하고는 :

func Unmarshal(data []byte, v interface{}) error 

가 오류를 반환 참조하십시오. 그 안에 추가,

err = json.Unmarshal(body, &record) 
perror(err) 

그것은 유니 코드 오류입니다 - 당신은 decode the UTF-16 data해야합니다.

어떻게해야합니까? this answer을보십시오. 기본적으로 body, err := ioutil.ReadAll(res.Body)과 같이 본문을 읽으면 UTF-16 바이트를 문자열로 디코드하려고합니다. 거기에 많은 일이 있지만, 우리는 몇 가지 자유를 취할 수 있습니다 : 예를 들어, 크롬에서 URL을 당겨, 브라우저는 그것이 UTF - 16 르임을 알려줍니다. ByteOrder 탐지를 건너 뛸 수 있습니다. 그래서 여기에 핵심이 기능입니다 :

func UTF16BytesToString(b []byte, o binary.ByteOrder) string { 
    utf := make([]uint16, (len(b)+(2-1))/2) 
    for i := 0; i+(2-1) < len(b); i += 2 { 
     utf[i/2] = o.Uint16(b[i:]) 
    } 
    if len(b)/2 < len(utf) { 
     utf[len(utf)-1] = utf8.RuneError 
    } 
    return string(utf16.Decode(utf)) 
} 

우리의 바이트 순서를 알고 그것을 전달은,이 UTF-16 문자열로 순진한 바이트 배열을 변환합니다. 사용자 OneOfOne의 comment 덕분에 BOM을 쉽게 감지 할 수 있습니다.

결과 :

package main 

import (
    "encoding/binary" 
    "encoding/json" 
    "fmt" 
    "io/ioutil" 
    "net/http" 
    "unicode/utf16" 
    "unicode/utf8" 
) 

const alertsUrl = "http://www.oref.org.il/WarningMessages/alerts.json" 

type Record struct { 
    Id string `json:id` 
    Title string `json:title` 
    Data []string `json:data` 
} 

// LazyUTF16BytesToString converts UTF-16 encoded bytes, in big or little endian byte order, 
// to a UTF-8 encoded string. 
func LazyUTF16BytesToString(b []byte) string { 
    if len(b)%2 != 0 { 
     panic("len(b) % 2 != 0") 
    } 

    var codec binary.ByteOrder = binary.LittleEndian 
    if b[0] == 0xFE && b[1] == 0xFF { //check and strip the BOM 
     b = b[2:] 
     codec = binary.BigEndian 
    } else if b[0] == 0xFF && b[1] == 0xFE { 
     b = b[2:] 
    } 

    utf := make([]uint16, (len(b)+(2-1))/2) 
    for i := 0; i+(2-1) < len(b); i += 2 { 
     utf[i/2] = codec.Uint16(b[i:]) 
    } 
    if len(b)/2 < len(utf) { 
     utf[len(utf)-1] = utf8.RuneError 
    } 
    return string(utf16.Decode(utf)) 
} 

func main() { 
    client := &http.Client{} 
    req, err := http.NewRequest("GET", alertsUrl, nil) 
    perror(err) 

    req.Header.Add("Content-Type", "application/json; charset=utf-8") 
    res, err := client.Do(req) 
    perror(err) 

    defer res.Body.Close() 
    body, err := ioutil.ReadAll(res.Body) 
    perror(err) 

    bodyString := LazyUTF16BytesToString(body) 

    var record Record 
    err = json.Unmarshal([]byte(bodyString), &record) 
    perror(err) 
    fmt.Println(record) 
} 

func perror(err error) { 
    if err != nil { 
     panic(err) 
    } 
} 
+0

고마워, 나는 그걸 –

+0

이렇게 시도 할 것이다 ... Unmarshal 메서드는 바이트 배열을 얻는다. 어떻게 해독 결과를 비 정렬화할 수 있습니까? –

+1

언 마샬링하기 전에 디코딩을해야합니다. 세부 사항이 추가되었습니다. – pswaminathan