<%@ WebHandler Language="C#" Class="TaiwanZipJson" %>
using System;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
public class TaiwanZipJson : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
XDocument xd = XDocument.Load(context.Server.MapPath(
"~/App_Data/zip32_10105_2012_0810upd.xml"));
var filtered = xd.Root.Elements("zip32")
//使用Elements("zip32")取出所有節點,用Select轉成物件
.Select(o => new
{
City = o.Element("City").Value,
Area = o.Element("Area").Value,
ZipCode = o.Element("Zip5").Value.Substring(0, 3)
})
//針對一些例外資料,進行修正
.Select(o => {
string area = o.Area;
string city = o.City;
//修正行政區域: 新竹市與嘉義市不分區
if (city == "新竹市" || city == "嘉義市")
area = city;
//南海諸島在行政上應隸屬高雄市
else if (city == "南海島")
city = "高雄市";
//釣魚台行政區域應屬宜蘭縣
else if (city == "釣魚台")
city = "宜蘭縣";
//由於匿名類別的屬性都是唯讀的,修正後重新定義新類別傳回
return new
{
City = city,
Area = area,
ZipCode = o.ZipCode
};
})
//以City/Area/ZipCode進行GroupBy, 主要在於統計出現的筆數
//留待之後同一ZipCode有多組City/Area時,判斷誰是多數
.GroupBy(o => string.Format("{0}/{1}/{2}",
o.City, o.Area, o.ZipCode))
//GroupBy後,操作的對象會變成特殊的IGrouping介面(即Select中的g)
//http://msdn.microsoft.com/en-us/library/bb344977.aspx
//.Key則是分群依據的屬性值
//由g本身可以做First()/Last()/Count()等標準LINQ操作
.Select(g => {
//同一Group的City/Area/ZipCode都相同,取第一筆當代表
var o = g.First();
//再傳回新的匿名類別,加上同City/Area/ZipCode的資料筆數
return new
{
o.City,
o.Area,
o.ZipCode,
RowCount = g.Count()
};
});
//24888之Area標為新莊區,但248為五股區的三碼區號
//利用GroupBy挑出這種少數特例加以剔除
var excep = filtered.GroupBy(o => o.ZipCode)
//找出同一郵遞區號由兩個區域以上共用擁有者
.Where(g => g.Count() > 1)
.Select(o => new
{
o.Key,
//將同郵遞區號的區域做成集合
Areas = o.ToList()
});
context.Response.Write("/** 以下郵遞區號被跨行政區使用,筆數少者刪除\r\n");
foreach (var e in excep) {
//Debug用,顯示害群之馬
context.Response.Write(
e.Key + "=>" + string.Join(",", e.Areas.Select(o =>
string.Format("{0}/{1}({2})", o.City, o.Area, o.RowCount)).ToArray()) +
"\r\n"
);
//刪除筆數少者: 以筆數由大至小排序,只保留第一筆,其餘刪除
filtered =
filtered.Except(e.Areas.OrderByDescending(o => o.RowCount).Skip(1));
}
context.Response.Write("**/\r\n");
//產生以城市名稱為Key, JObject為Value的Dictionary
Dictionary<string, JProperty> cities =
//取出不重複的城市名清單
filtered.Select(o => o.City).Distinct()
//利用ToDictionary()直接轉成Dictionary
.ToDictionary(o => o, o => new JProperty(
o, new JObject()));
//將所有的郵遞區號跟區域名歸檔到該城市JObject中
foreach (var a in filtered)
{
(cities[a.City].Value as JObject)
.Add(new JProperty(a.Area, a.ZipCode));
}
JObject result = new JObject();
//依城市在XML的出現順序加入各城市的JObject
foreach (var city in
xd.Root.Descendants("City").Select(o => o.Value).Distinct())
{
if (cities.ContainsKey(city))
result.Add(cities[city]);
}
//傳回JSON
context.Response.Write(result.ToString());
}
public bool IsReusable {
get {
return false;
}
}
}