您的位置:首页 > 编程语言 > Go语言

[笔记]Go语言实现同一结构体适配多种消息源

2015-04-03 18:19 513 查看
问题:

提供天气信息的网站有很多,每家的数据及格式都不同,为了适配各种不同的天气接口,写了如下程序。

代码如下:

package main

import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
)

var s string = `
{
"error": 0,
"status": "success",
"date": "2015-03-26",
"results": [
{
"test": [
[
"fuck",
"shit"
],
{
"ao": "xxx"
},
"vfe"
],
"currentCity": "郑州",
"pm25": "95",
"index": [
{
"title": "穿衣",
"zs": "较冷",
"tipt": "穿衣指数",
"des": "建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。"
},
{
"title": "洗车",
"zs": "不宜",
"tipt": "洗车指数",
"des": "不宜洗车,未来24小时内有雨,如果在此期间洗车,雨水和路上的泥水可能会再次弄脏您的爱车。"
},
{
"title": "旅游",
"zs": "适宜",
"tipt": "旅游指数",
"des": "温度适宜,又有较弱降水和微风作伴,会给您的旅行带来意想不到的景象,适宜旅游,可不要错过机会呦!"
},
{
"title": "感冒",
"zs": "少发",
"tipt": "感冒指数",
"des": "各项气象条件适宜,无明显降温过程,发生感冒机率较低。"
},
{
"title": "运动",
"zs": "较不宜",
"tipt": "运动指数",
"des": "有降水,推荐您在室内进行健身休闲运动;若坚持户外运动,须注意保暖并携带雨具。"
},
{
"title": "紫外线强度",
"zs": "最弱",
"tipt": "紫外线强度指数",
"des": "属弱紫外线辐射天气,无需特别防护。若长期在户外,建议涂擦SPF在8-12之间的防晒护肤品。"
}
],
"weather_data": [
{
"date": "周四 03月26日 (实时:12℃)",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/zhenyu.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
"weather": "阵雨转多云",
"wind": "微风",
"temperature": "12 ~ 4℃"
},
{
"date": "周五",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
"weather": "晴",
"wind": "微风",
"temperature": "16 ~ 8℃"
},
{
"date": "周六",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
"weather": "晴转多云",
"wind": "微风",
"temperature": "22 ~ 9℃"
},
{
"date": "周日",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
"weather": "晴",
"wind": "微风",
"temperature": "25 ~ 11℃"
}
]
}
]
}
`

// 天气
type Weather struct {
Error_Code string `json:"error_code"` //错误码  0没有错误
Status     string `json:"status"`     // 状态描述, success 成功
Result     Result `json:"result"`     // 天气状况
}

// 天气结果
type Result struct {
Now         Real
LivingIndex []Indicate `json:"living_index"` //生活指数
Future      []ForeCast `json:"future"`       //未来几天的预报,包括当天
}

// 实时报告
type Real struct {
City          string `json:"city"`           // 城市
Temperature   string `json:"temperature"`    // 当前温度
WindDirection string `json:"wind_direction"` // 风向
WindStrength  string `json:"wind_strength"`  // 风强度
Humidity      string `json:"humidity"`       // 湿度
PM25          string `json:"pm25"`           // PM2.5
}

// 预报
type ForeCast struct {
Temperature string `json:"temperature"` // 温度范围
Weather     string `json:"weather"`     // 天气  (晴,多云,阴转多云)
Wind        string `json:"wind"`        // 风向和强度
Week        string `json:"week"`        // 星期几
Date        string `json:"date"`        // 日期
}

type Indicate struct {
Title       string `json:"titile"` // 指数标题
Status      string `json:"status"` //指数状态 (适宜,不宜)
Description string `json:"desc"`   //描述信息
}

func NewWeather() *Weather {
return NewWeatherWithNum(6, 4)
}

func NewWeatherWithNum(livingIndexNum, forecastNum int) *Weather {
w := &Weather{}
w.Result.LivingIndex = make([]Indicate, livingIndexNum)
w.Result.Future = make([]ForeCast, forecastNum)
return w
}

type ElementExtractor struct {
Err error
m   map[string]interface{}
r   *regexp.Regexp
}

func NewElementExtractor(jsonString string) *ElementExtractor {
ee := &ElementExtractor{r: regexp.MustCompile(`(.*)\[(\d+)\]+`)}
ee.Err = json.Unmarshal([]byte(jsonString), &ee.m)
return ee
}

func (ee *ElementExtractor) ExtractElementByPattern(patten string) (string, error) {
if ee.Err != nil {
return "", ee.Err
}

var mm map[string]interface{} = ee.m
var sa []interface{}

patten = strings.Replace(patten, "][", "].[", -1)

for _, k := range strings.Split(patten, ".") {
ki := ee.r.FindStringSubmatch(k)
if len(ki) == 3 {
j, _ := strconv.Atoi(ki[2])
if ki[1] != "" {
sa = mm[ki[1]].([]interface{})
}

switch s := sa[j].(type) {
case string:
return s, nil
case map[string]interface{}:
mm = s
case []interface{}:
sa = sa[j].([]interface{})
default:
return fmt.Sprintf("%v", s), nil
}
} else {
switch s := mm[k].(type) {
case string:
return s, nil
case map[string]interface{}:
mm = s
default:
return fmt.Sprintf("%v", s), nil
}
}
}

ee.Err = errors.New("Pattern Error: " + patten)
return "", ee.Err
}

func main() {
ee := NewElementExtractor(s)
w := NewWeather()

w.Status, _ = ee.ExtractElementByPattern("status")
w.Error_Code, _ = ee.ExtractElementByPattern("error")
w.Result.Now.City, _ = ee.ExtractElementByPattern("results[0].currentCity")
w.Result.Now.PM25, _ = ee.ExtractElementByPattern("results[0].pm25")
w.Result.Future[2].Date, _ = ee.ExtractElementByPattern("results[0].weather_data[2].date")
w.Result.LivingIndex[0].Title, _ = ee.ExtractElementByPattern("results[0].index[0].title")
w.Result.Future[2].Temperature, _ = ee.ExtractElementByPattern("results[0].weather_data[2].temperature")
w.Result.Now.PM25, _ = ee.ExtractElementByPattern("results[0].test[0][1]")
w.Result.Now.WindDirection, _ = ee.ExtractElementByPattern("results[0].test[1].ao")
w.Result.Now.WindStrength, _ = ee.ExtractElementByPattern("results[0].test[2]")

if ee.Err != nil {
fmt.Println(ee.Err)
} else {
fmt.Println(w)
}
}


运行结果:

&{0 success {{郑州  xxx vfe  shit} [{穿衣  } {  } {  } {  } {  } {  }] [{    } {    } {22 ~ 9℃    周六} {    }]}}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: