XML转换为JSON多重嵌套

时间:2016-05-04 19:58:50

标签: json xml go nested output

我试图编写代码将XML转换为JSON。我试图翻译的XML如下......

(只是一个片段)

`<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情况下。但是对于xml:"current_observation>display_location>state_name"这样的两个级别的嵌套案例,我无法弄清楚如何创建第一个级别,在本例中为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"
      }
}

1 个答案:

答案 0 :(得分:2)

您可以使用结构图或地图图。我将从地图图开始给出两者的一些例子。该类型将声明为;

char getkey (int minimo, int maximo, int alphalen, int index, char alpha[])  
{  
    int cociente, residuo, cont;
    int i = 0;
    char cand[maximo+1];
    char candidate[maximo+1];

    while (index != 0)
    {
        cociente = index / alphalen;
        residuo = index%alphalen;
        cand[i] = residuo;
        index = cociente;
        i+=1;
    }

    for (cont=i-1; cont>=0; cont--)  
    {   
        int pos = cand [cont];
        candidate[i] = alpha[pos];      
    }
    return candidate;
}

在这种情况下,您有一个以字符串作为键的映射,值是另一个具有键和值字符串的映射。因此,当你整理你的json时,你最终会得到类似的东西;

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

如果说你想打印标题,你会这样做;

"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然后map选项会自动取消此数据的结构以及struct选项会排除它,因为Go中没有任何对象/类型的映射。

我个人更喜欢结构路线,但因情况而异。对于你的应用程序,地图可能更好,因为你没有使用输入(它以xml形式出现)而你只想打印它,你真的不必处理previous_observation的细节,如果它里面有3个对象,它们都将按预期输出,如果它是5,它将是相同的。对于结构,您必须明确定义每个单独的字段,如果您只是转换输入,那么这不是必需的。结构的优点更多用于以后你有类型安全的地方,虽然在这种情况下,我会说它们仍然相当等同,因为例如你想要访问图像中的某些东西,比如current_observation你'我必须执行检查以确保Image不是nil,例如;

CurrentObservation.Image.Title

使用地图你基本上有相同的开销,只有你检查是否存在一个键而不是检查其中一个内部结构是否为零。

编辑:使用复合文字语法初始化地图地图的示例;

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