学了一段时间的Web服务,今天做了一个Web服务,利用YAHOO的公开天气API做自己的Web服务,主要是想练练手。现在把过程和心得分享给大家。
求教:这个Web服务还有个不完善的地方,Web服务的 CityNameToCityNum方法,这个最重要,他是把省会和直辖市的名字转换为编号,因为YAHOO传的参数不是城市名字的区号,全是自己的,而我又想不到更好的获得YAHOO城市对应的编号的方法,所以就创建了HASHTABLE存储了中国的各个省会城市和直辖市,希望有高手提出更好的方法,能不用这样,直接找YAHOO获取编号,提取更多的城市,而不用把所有的中国所有的城市全写在HASHTABLE里。
Web服务地址:http://www.h2bbs.com/Weather/Weather.asmx
原理:
在Yahoo的Developer Network
http://developer.yahoo.com/weather/
详细地介绍了Yahoo天气预报的API调用方法,这里用C#来实现,本文主要是利用它的API做Web服务,其它的应用由网友们自由发挥
首先了解Yahoo Weather Api的RSS Response格式(这是下午我查我家银川天气时返回的RSS):
<rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
<channel>
<title>Yahoo! Weather - Yinchuan, CH</title>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/Yinchuan__CH/*http://kb.cnblogs.com/page/42993/%3C/span%3E%3Cspan%20style=" target=_blank>http://kb.cnblogs.com/page/42993/%3C/span%3E%3Cspan%20style=</link>
<description>Yahoo! Weather for Yinchuan, CH</description>
<language>en-us</language>
<lastBuildDate>Tue, 14 Oct 2008 11:00 am CST</lastBuildDate>
<ttl>60</ttl>
<yweather:location city="Yinchuan" region="" country="CH"/>
<yweather:units temperature="F" distance="mi" pressure="in" speed="mph"/>
<yweather:wind chill="56" direction="360" speed="4" />
<yweather:atmosphere humidity="56" visibility="999" pressure="" rising="0" />
<yweather:astronomy sunrise="7:03 am" sunset="6:19 pm"/>
<image>
<title>Yahoo! Weather</title>
<width>142</width>
<height>18</height>
<link>http://weather.yahoo.com</link>
<url>http://l.yimg.com/us.yimg.com/i/us/nws/th/main_142b.gif</url>
</image>
<item>
<title>Conditions for Yinchuan, CH at 11:00 am CST</title>
<geo:lat>38.48</geo:lat>
<geo:long>106.22</geo:long>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/Yinchuan__CH/*http://kb.cnblogs.com/page/42993/%3C/span%3E%3Cspan%20style=" target=_blank>http://kb.cnblogs.com/page/42993/%3C/span%3E%3Cspan%20style=</link>
<pubDate>Tue, 14 Oct 2008 11:00 am CST</pubDate>
<yweather:condition text="Mostly Cloudy" code="28" temp="56" date=
"Tue, 14 Oct 2008 11:00 am CST" />
<description>
<![CDATA[
<img src="
//l.yimg.com/us.yimg.com/i/us/we/52/28.gif" target=_blank>//l.yimg.com/us.yimg.com/i/us/we/52/28.gif" border=0 alt='点击查看大图' onload='javascript:if(this.width>screen.width-450)this.width=screen.width-450'>"/><br />
<b>Current Conditions:</b><br />
Mostly Cloudy, 56 F<BR />
<BR /><b>Forecast:</b><BR />
Tue - Mostly Cloudy. High: 68 Low: 47<br />
Wed - Partly Cloudy. High: 70 Low: 44<br />
<br />
<a href="Full'>http://us.rd.yahoo.com/dailynews/rss/weather/Yinchuan__CH/*http://weather.yahoo.com/forecast/CHXX0259_f.html">Full Forecast at Yahoo! Weather</a><BR/>
(provided by The Weather Channel)<br/>
]]>
</description>
<yweather:forecast day="Tue" date="14 Oct 2008" low="47" high="68" text
="Mostly Cloudy" code="28" />
<yweather:forecast day="Wed" date="15 Oct 2008" low="44" high="70" text
="Partly Cloudy" code="30" />
<guid isPermaLink="false">CHXX0259_2008_10_14_11_00_CST</guid>
</item>
</channel>
</rss>
<!-- api5.weather.sp1.yahoo.com compressed/chunked Mon Oct 13 22:30:39 PDT
2008 -->
其中最重要的是后面的几行,查询当天和第二天的天气情况,我们要获取的天气信息就在里面,代码如下:
="Mostly Cloudy" code="28" />
<yweather:forecast day="Wed" date="15 Oct 2008" low="44" high="70" text
="Partly Cloudy" code="30" />
我们所需要用到的Node是/rss/channel/item/yweather: forecast;这个节点里的东西是我们需要的。
知道了这些,我们接下来要做的就是在VS中建立WEB服务,并添加下面的代码:
{
/// <summary>
/// Weather 的摘要说明
/// </summary>
[WebService(Name = "天气预报Web服务", Namespace = "http://www.h2bbs.com/WebService/Weather.asmx", Description = "利用YAHOO公开的API接口,在Web服务实现公开的天气预报调用服务。")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Weather : System.Web.Services.WebService
{
[WebMethod(Description = "根据城市的名称返回该城市的天气预报情况,只能查询省会和直辖市的天气情况。")]
public DataSet GetWeather(string strCityName)
{
string strXml = "http://xml.weather.yahoo.com/forecastrss?p=CHXX" + CityNameToCityNum(strCityName);
XmlDocument Weather = new XmlDocument();
Weather.Load(strXml);
XmlNamespaceManager namespacemanager = new
XmlNamespaceManager(Weather.NameTable);
namespacemanager.AddNamespace("yweather",
"http://xml.weather.yahoo.com/ns/rss/1.0");
XmlNodeList nodes = Weather.SelectNodes("/rss/channel/item/yweather:forecast", namespacemanager);
//XmlNodeList nodes = Weather.GetElementsByTagName("forecast", "http://xml.weather.yahoo.com/ns/rss/1.0");
DataSet dstWeather = new DataSet();
DataTable dtblWeather = new DataTable("Weather");
dstWeather.Tables.Add(dtblWeather);
dstWeather.Tables["Weather"].Columns.Add("Date", typeof(string));
dstWeather.Tables["Weather"].Columns.Add("Week", typeof(string));
dstWeather.Tables["Weather"].Columns.Add("Weather", typeof(string));
dstWeather.Tables["Weather"].Columns.Add("Tlow", typeof(string));
dstWeather.Tables["Weather"].Columns.Add("Thigh", typeof(string));
if (nodes.Count > 0)
{
foreach (XmlNode node in nodes)
{
DataRow drowWeather = dstWeather.Tables["Weather"].NewRow();
drowWeather["Date"] = EmonthToCmonth(node.SelectSingleNode
("@date").Value.ToString());
drowWeather["Week"] = EweekToCweek(node.SelectSingleNode
("@day").Value.ToString()) + "(" + node.SelectSingleNode("@day").Value.ToString()
+ ")";
drowWeather["Weather"] = node.SelectSingleNode("@text").Value;
drowWeather["Tlow"] = FToC(int.Parse(node.SelectSingleNode
("@low").Value)) + "℃";
drowWeather["Thigh"] = FToC(int.Parse(node.SelectSingleNode
("@high").Value)) + "℃";
dstWeather.Tables["Weather"].Rows.Add(drowWeather);
}
return dstWeather;
}
else
{
DataRow drowNone = dstWeather.Tables["Weather"].NewRow();
drowNone["Week"] = "None";
drowNone["Weather"] = "None";
drowNone["Tlow"] = "None";
drowNone["Thigh"] = "None";
dstWeather.Tables["Weather"].Rows.Add(drowNone);
return dstWeather;
}
return dstWeather;
}
/// <summary>
/// 从华氏转换成摄氏
/// </summary>
/// <param name="f">华氏度</param>
/// <returns></returns>
private string FToC(int f)
{
return Math.Round((f - 32) / 1.8, 1).ToString();
}
/// <summary>
/// 从星期英文缩写转汉字
/// </summary>
/// <param name="strEweek">星期的英文缩写</param>
/// <returns></returns>
private string EweekToCweek(string strEweek)
{
switch (strEweek)
{
case "Mon":
return "星期一";
break;
case "Tue":
return "星期二";
break;
case "Wed":
return "星期三";
break;
case "Thu":
return "星期四";
break;
case "Fri":
return "星期五";
break;
case "Sat":
return "星期六";
break;
case "Sun":
return "星期日";
break;
default:
return "传参错误";
break;
}
}
/// <summary>
/// 从月英文缩写转汉字
/// </summary>
/// <param name="strReplace">需要替换的年月日</param>
/// <returns></returns>
private string EmonthToCmonth(string strReplace)
{
return Convert.ToDateTime(strReplace).ToString("yyyy年MM月dd日");
}
/// <summary>
/// 根据城市名称返回城市编号
/// </summary>
/// <param name="strCityName">城市名称</param>
/// <returns></returns>
private string CityNameToCityNum(string strCityNameToNum)
{
//中国各个省会和直辖市对应的查询代码
Hashtable htWeather = new Hashtable();
htWeather.Add("北京", "0008");
htWeather.Add("天津", "0133");
htWeather.Add("杭州", "0044");
htWeather.Add("合肥", "0448");
htWeather.Add("上海", "0116");
htWeather.Add("福州", "0031");
htWeather.Add("重庆", "0017");
htWeather.Add("南昌", "0097");
htWeather.Add("香港", "0049");
htWeather.Add("济南", "0064");
htWeather.Add("澳门", "0512");
htWeather.Add("郑州", "0165");
htWeather.Add("呼和浩特", "0249");
htWeather.Add("乌鲁木齐", "0135");
htWeather.Add("长沙", "0013");
htWeather.Add("银川", "0259");
htWeather.Add("广州", "0037");
htWeather.Add("拉萨", "0080");
htWeather.Add("海口", "0502");
htWeather.Add("南宁", "0100");
htWeather.Add("成都", "0016");
htWeather.Add("石家庄", "0122");
htWeather.Add("贵阳", "0039");
htWeather.Add("太原", "0129");
htWeather.Add("昆明", "0076");
htWeather.Add("沈阳", "0119");
htWeather.Add("西安", "0141");
htWeather.Add("长春", "0010");
htWeather.Add("兰州", "0079");
htWeather.Add("西宁", "0236");
htWeather.Add("南京", "0099");
object cityNum = htWeather[strCityNameToNum];
if (cityNum == null)
{
return "City not found";
}
else
{
return cityNum.ToString();
}
}
}
}
别忘了"using System.Xml;"哦!
Web服务的代码中有一个Web公开方法,四个私有方法:
(1)GetWeather方法是公共方法,提供Web调用。
(2)FToC方法,他主要是把RSS返回的华氏温度转换成摄氏温度,其实这一步可以不用的,当初没发现,URL中加点参数就返回的是摄氏温度。
(3)EweekToCweek方法,他主要是把英文的星期缩写变成中文。
(4)EmonthToCmonth方法,它主要是把英文的月份缩写变成中文,并重新排序。
(5)CityNameToCityNum方法,这个最重要,他是把省会和直辖市的名字转换为编号,因为YAHOO传的参数不是城市名字的区号,全是自己的,而我又想不到更好的获得YAHOO城市对应的编号的方法,所以就只能支持这么几个城市了,希望有高手提出更好的方法,能不用这样,直接找YAHOO获取编号。
查询个中国随便的省会,效果如下
- <DataSet xmlns="http://www.h2bbs.com/WebService/Weather.asmx">
- <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:
UseCurrentLocale="true">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element name="Weather">
- <xs:complexType>
- <xs:sequence>
<xs:element name="Date" type="xs:string" minOccurs="0" />
<xs:element name="Week" type="xs:string" minOccurs="0" />
<xs:element name="Weather" type="xs:string" minOccurs="0" />
<xs:element name="Tlow" type="xs:string" minOccurs="0" />
<xs:element name="Thigh" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
- <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
- <NewDataSet xmlns="">
- <Weather diffgr:id="Weather1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<Date>2008年10月14日</Date>
<Week>星期二(Tue)</Week>
<Weather>Clear</Weather>
<Tlow>16.1℃</Tlow>
<Thigh>26.7℃</Thigh>
</Weather>
- <Weather diffgr:id="Weather2" msdata:rowOrder="1" diffgr:hasChanges=
"inserted">
<Date>2008年10月15日</Date>
<Week>星期三(Wed)</Week>
<Weather>Sunny</Weather>
<Tlow>16.7℃</Tlow>
<Thigh>28.3℃</Thigh>
</Weather>
</NewDataSet>
</diffgr:diffgram>
</DataSet>
写完了!最后希望能给大家带来收获!