2016-05-04 6 views
1

XMLをJSONに変換するコードを記述しようとしています。私は次のようである翻訳しようとしているXML ...XMLをJSONに複数ネスティング

(ジャストスニペット)

`<version>0.1</version> 
    <termsofService>http://www.wunderground.com/weather/api/d/terms.html</termsofService> 
    <features> 
     <feature>conditions</feature> 
    </features> 
    <current_observation> 
     <image> 
     <url>http://icons.wxug.com/graphics/wu2/logo_130x80.png</url> 
     <title>Weather Underground</title> 
     <link>http://www.wunderground.com</link> 
     </image> 
     <display_location> 
     <full>Kearney, MO</full> 
     <city>Kearney</city> 
     <state>MO</state> 
     <state_name>Missouri</state_name>` 

現在のコード:

`package main 

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

type reportType struct{ 
    Version xml.CharData  `xml:"version"` 
    TermsOfService xml.CharData `xml:"termsofService" 
    ` 
    Features xml.CharData  `xml:"features>feature"` 
    Full  xml.CharData  `xml:"current_observation>display_location>full"` 
    StateName xml.CharData  `xml:"current_observation>display_location>state_name"` 
    WindGust xml.CharData  `xml:"current_observation>observation_location>full"` 
    Problem myErrorType  `xml:"error"` 
} 
type myErrorType struct{ 
    TypeOfError xml.CharData `xml:"type"` 
    Desciption xml.CharData `xml:"description"` 
} 
type reportTypeJson struct{ 
    Version  string `json:"version"`; 
    TermsOfService string `json:"termsofService"`; 
    Features map[string]string `json:"features"`; 
    Full  map[string]string `json:"display_location"`; 
    WindGust map[string]string `json:"observation_location"` 

} 
func main() { 
    fmt.Println("data is from WeatherUnderground.") 
    fmt.Println("https://www.wunderground.com/") 
    var state, city string 
    str1 := "What is your state?" 
    str2 := "What is your city?" 
    fmt.Println(str1) 
    fmt.Scanf("%s", &state) 
    fmt.Println(str2) 
    fmt.Scanf("%s", &city) 
    baseURL := "http://api.wunderground.com/api/"; 
    apiKey := "3hunna" 
    var query string 

    //set up the query 
    query = baseURL+apiKey + 
    "/conditions/q/"+ 
    url.QueryEscape(state)+ "/"+ 
    url.QueryEscape(city)+ ".xml" 
    fmt.Println("The escaped query: "+query) 

    response, err := http.Get(query) 
    doErr(err, "After the GET") 
    var body []byte 
    body, err = ioutil.ReadAll(response.Body) 
    doErr(err, "After Readall") 
    fmt.Println(body); 
    fmt.Printf("The body: %s\n",body) 

    //Unmarshalling 
    var report reportType 
    xml.Unmarshal(body, &report) 
    fmt.Printf("The Report: %s\n", report) 
    fmt.Printf("The description is [%s]\n",report.Problem.Desciption) 

    //Now marshal the data out in JSON 
    var data []byte 
    var output reportTypeJson 
    output.Version = string(report.Version); 
    output.TermsOfService = string(report.TermsOfService) 

    output.Features= map[string]string{"feature":string(report.Features)} // allocate a map, add the 'features' value to it and assign it to output.Features 
    output.Full=map[string]string{"full":string(report.Full),"state_name":string(report.StateName)} 
    output.WindGust=map[string]string{"full":string(report.WindGust)} 
    data,err = json.MarshalIndent(output,"","  ") 
    doErr(err, "From marshalIndent") 
    fmt.Printf("JSON output nicely formatted: \n%s\n",data) 


} 
func doErr(err error, message string){ 
    if err != nil{ 
     log.Panicf("ERROR: %s %s \n", message, err.Error()) 
    } 


} 

あなたが見ることができるように、私が使用しているマップfeaturesの場合のように1つのレベルのネストをマッピングします。しかし、xml:"current_observation>display_location>state_name"のような2段階の入れ子のケースでは、最初のレベルを作成する方法はわかりません。この場合はcurrent_observationsです。どうにかして地図のマップを作成する方法がありますか?私は今非常に混乱しているので、任意のすべてのアイデアは非常に感謝しています、あなたの時間をありがとう!

と出力:

JSON output nicely formatted: 
{ 
     "version": "0.1", 
     "termsofService": "http://www.wunderground.com/weather/api/d/terms.html", 
     "features": { 
      "feature": "conditions" 
     }, 
     "display_location": { 
      "full": "Kearney, MO", 
      "state_name": "Missouri" 
     }, 
     "observation_location": { 
      "full": "Stonecrest, Kearney, Missouri" 
     } 
} 

答えて

2

あなたは構造体やマップのマップのいずれかを使用することができます。地図の地図から始めて、両方の例をいくつか紹介します。型は次のように宣言されます。

CurrentObservation map[string]map[string]string `json:"current_observation"` 

この場合、キーとして文字列を持つマップがあり、値はキーと値の両方の文字列を持つ別のマップです。その結果、あなたがあなたのjsonをマーシャリングするとき、あなたは何かのようになります。

"current_observation" { 
    "image": { // first level where the value is a map[string]string 
      "title":"Weather Underground" // inner map, string to string 
     } 
} 

タイトルを印刷するだけの場合は、

fmt.Println(reportJson.CurrentObservation["image"]["title"]) 

データがかなり静的に見えるので、代わりに構造体を使用することもできます。あなたはこのようなものを使うでしょう。

CurrentObservation CurrentObservation `json:"current_observation"` 

type CurrentObservation struct { 
    Image Image `json:"image"` 
} 

type Image struct { 
    Url string `json:"url"` 
    Title string `json:"title"` 
    Link string `json:"link"` 
} 

両方のオプションは、異なる入力に対して異なる動作をすることができますが、どちらのオプションも同じ出力を生成します。たとえば、別のバージョンのcurrent_observationが入力として受け取られた場合、その中に別のネストされた項目があるとします。previous_observationこの場合、マップオプションは自動的にこのデータをunmarhsalしますが、構造オプションによっては除外されますGoの任意のオブジェクト/タイプへのマッピング。

私は可能な限り構造化ルートを好みますが、大文字と小文字が異なります。あなたのアプリケーションでは、入力を使って作業していないので(xmlとして提供されている)、マップを印刷したいだけなので、mapはおそらくより良いでしょう。current_observationの詳細を扱う必要はありません。その中のオブジェクトは、すべて期待どおりに出力されますが、5の場合は同じになります。構造体では、入力を変換するだけの場合には、実際には必要ないすべての単一フィールドを明示的に定義する必要があります。この構造体の利点は、後でタイプセーフティがある場所での使用のためですが、この場合は、例えば画像内の何かにアクセスしたいときなどにはいつでもかなり同等であると言います。CurrentObservation.Image.Titleのように実行する必要がありますImageがnilでないことを確認するためのチェック。内部構造体の一つがnilであるかどうか、あなたは基本的に唯一のキーの存在をチェックするのではなくチェックしている、同じオーバーヘッドを持っているマップと

if CurrentObservation.Image != nil { 
    fmt.Println(CurrentObservation.Image.Title) 
} 

EDIT:複合リテラル構文を使用してマップのマップを初期化する例。

reportJson.CurrentObservation := map[string]map[string]string { 
      "display_location": map[string]string { 
       "full": report.Full, 
       "state_name": report.StateName, 
      }, 
    } 
+0

地図の地図は、私がうまくいくと思ったものでしたが、どうやったらそれを作成するのですか? –

+0

@BeccaBohemでは、ここでも複合リテラル構文を使用できます。追加のレベルの入れ子があるので、ちょっと複雑です。ここでは演技の例がありますが、スニペットでも編集します。 https://play.golang.org/p/yO21iZMBfy – evanmcdonnal