CODE-XML資料的整併轉換範例
1 | 7,187 |
為了開發地址輸入控件,需要台灣地區郵遞區號及地址路名的基本資料。中華郵政網站提供了完整的3+2碼式郵遞區號對照表可供下載(3+2郵遞區號資料XML檔(自解壓縮檔) 98/11 ),是絕佳的權威資料來源:
排版顯示純文字
<NewDataSet>
<zip32>
<zipcode>10058</zipcode>
<city>台北市</city>
<area>中正區 </area>
<road>八德路1段 </road>
<scoop>全 </scoop>
</zip32>
<zip32>
<zipcode>10070</zipcode>
<city>台北市</city>
<area>中正區 </area>
<road>三元街 </road>
<scoop>雙 48號以下 </scoop>
</zip32>
<zip32>
<zipcode>10079</zipcode>
<city>台北市</city>
<area>中正區 </area>
<road>三元街 </road>
<scoop>雙 50號以上 </scoop>
</zip32>
不過,依手邊的應用上,只打算使用三碼郵遞區號及路名提示,因此打算將資料整成以下的格式,只保留必要資訊,降低檔案大小(原本高達12MB)也提升查詢效率:
排版顯示純文字
<?xml version="1.0" encoding="utf-8"?>
<AddressData>
<Zip T="100">
<City T="台北市">
<Area T="中正區">
<Road T="八德路1段" />
<Road T="三元街" />
<Road T="中山北路1段" />
<Road T="仁愛路2段" />
<Road T="公園路" />
<Road T="水源路" />
<Road T="汀州路2段" />
<Road T="汀州路3段" />
<Road T="和平西路1段" />
試寫了一下,程式比預期的簡單。藉著Extension Method跟LINQ to XML的協助,只花了不到60行,執行不到10秒鐘,就算出想要的結果,XML檔案也由原先的12MB,如期縮小到1.2MB。
程式碼分享如下,其中root.CreateOrGetElement(...).CreateOrGetElement(…).CreateOrGetElement(…)的寫法頗為有趣,很有寫jQuery的fu~~~
排版顯示純文字
using System.Linq;
using System.Xml.Linq;
namespace CompactZipXml
{
class Program
{
static void Main(string[] args)
{
XDocument xdRaw =
XDocument.Load("C:\\Temp\\zip32_9811.xml");
XDocument xdResult =
XDocument.Parse("<AddressData />");
XElement root = xdResult.Root;
//記錄目前的Area XML節點
XElement currentArea = null;
//逐一處理所有zip32
foreach (var z in xdRaw.Root.Elements().OrderBy(o => o.Element("city").Value).OrderBy(o => o.Element("area").Value))
{
//檢查目前區域,若不同則新建,相同則繼續沿用
string area = z.Element("area").Value.Trim();
if (currentArea == null ||
currentArea.Attribute("T").Value != area)
{
currentArea = root
.CreateOrGetElement("Zip", //只取3碼
z.Element("zipcode").Value.Substring(0, 3))
.CreateOrGetElement("City",
z.Element("city").Value.Trim())
.CreateOrGetElement("Area", area);
}
currentArea.CreateOrGetElement("Road",
z.Element("road").Value.Trim());
}
xdResult.Save("C:\\TEMP\\zip3.xml");
}
}
public static class ZipXmlExt
{
//利用Extension Method功能,為XEelement新增或取得特定子元素
public static XElement CreateOrGetElement(this XElement parent,
string elemName, string attValue)
{
var q = parent.Elements(elemName)
.Where(o => o.Attribute("T").Value == attValue)
.SingleOrDefault();
if (q != null)
return q;
else
{
XElement elem = new XElement(elemName);
elem.SetAttributeValue("T", attValue);
parent.Add(elem);
return elem;
}
}
}
}
Comments
# by blackie
太棒了~感謝貢獻