看 chou 大的 讀取文化部資料開放服務網資料 (1) 蠻有趣,也想試試在 Linux 下的指令模式,如何把該 XML 裡的值抓出。
觀察XML之格式
先下載該XML檔案
$ wget http://cloud.culture.tw/frontsite/trans/emapOpenDataAction.do?method=exportEmapXML\&typeId=F -O o.xml
--2013-10-05 07:10:46-- http://cloud.culture.tw/frontsite/trans/emapOpenDataAction.do?method=exportEmapXML&typeId=F
Resolving cloud.culture.tw (cloud.culture.tw)... 210.61.8.85
Connecting to cloud.culture.tw (cloud.culture.tw)|210.61.8.85|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/xml]
Saving to: ‘o.xml’
[ <=> ] 1,933,955 3.03MB/s in 0.6s
2013-10-05 07:10:47 (3.03 MB/s) - ‘o.xml’ saved [1933955]
該檔案輸出排列的不易觀察,利用以下指令來簡單地排列,好觀察要取哪些的值:
xmllint --format o.xml | less
<?xml version="1.0" encoding="UTF-8"?>
<XML_Head version="1.0" status="success" total="2247">
<emapItem>
<emap>
<Info groupTypeName="公共藝術" mainTypeName="公共藝術" mainTypePk="2828" name="聚沙成塔 Accumulating much from a little" representImage="http://cloud.culture.tw/e_upload_ccacloud/ccacloud/image/A0/B0/C-1/D-267/E-728/F-534/1364531871547.jpg" intro="此件作品設置於單位之大門廣場上,以具有代表錢幣之貝殼造型意像,運用鋼材層疊的創作手法,表現出「積少成多,聚沙成塔」之財稅集中的精神意涵,而其旋轉上身之造刑動勢,更營造出單位的朝氣與活力,讓往來之民眾更能體現場域之精神。" areaCode="407" cityName="
臺中市 西屯區" address="稅捐稽徵處" longitude="120.647237" latitude="24.1589" buildingYearName="P130-407-05" author="林舜龍、楊仁明、張明風 lin Shuen-Long, Yang Jen-Ming, Chang Ming-Feng" size="435*315*600cm" material="熱浸鍍鋅鋼板"/>
...
</emap>
</emapItem>
</XML_Head>
此 xmllint 的指令是包在 libxml2 的套件裡。
但後來發現 tidy 的指令排得更利於觀察些:
$ tidy -xml -utf8 -i -q o.xml |less
<?xml version="1.0" encoding="utf-8"?>
<XML_Head version="1.0" status="success" total="2247">
<emapItem>
<emap>
<Info groupTypeName="公共藝術" mainTypeName="公共藝術"
mainTypePk="2828" name="聚沙成塔 Accumulating much from a little"
representImage="http://cloud.culture.tw/e_upload_ccacloud/ccacloud/image/A0/B0/C-1/D-267/E-728/F-534/1364531871547.jpg"
intro="此件作品設置於單位之大門廣場上,以具有代表錢幣之貝殼造型意像,運用鋼材層疊的創作手法,
表現出「積少成多,聚沙成塔」之財稅集中的精神意涵,而其旋轉上身之造刑動勢,更營造出單位的朝氣與活力,讓往來之民眾更能體現場域之精神。"
areaCode="407" cityName="臺中市 西屯區" address="稅捐稽徵處"
longitude="120.647237" latitude="24.1589"
buildingYearName="P130-407-05"
author="林舜龍、楊仁明、張明風 lin Shuen-Long, Yang Jen-Ming, Chang Ming-Feng"
size="435*315*600cm" material="熱浸鍍鋅鋼板" />
<Info groupTypeName="公共藝術" mainTypeName="公共藝術"
mainTypePk="2829" name="所拾 Key"
representImage="http://cloud.culture.tw/e_upload_ccacloud/ccacloud/image/A0/B0/C-1/D-267/E-726/F-362/1364531873719.jpg"
intro="透過低頭側身的穿越,彷彿由內而外的淨化與蛻變。窄門是成功的代言,而低頭思苦的當時,澈悟
出成功所拾的所在。"
areaCode="406" cityName="臺中市 北屯區" address="中清路70-1號 大德樓穿堂後方"
longitude="120.669158" latitude="24.180345"
buildingYearName="P127-406-05" author="廖秀玲 Liao Xiu-Ling"
size="310*90*200" material="大理石、蛇岩" />
..
</emap>
</emapItem>
</XML_Head>
如果要抓裡面的 name,需要有工具做真正的解析XML的工作。這時就需要 xmlstarlet 這工具來進行。
解析XML的內容
先看此檔有什階層:
xml el o.xml
XML_Head
XML_Head/emapItem
XML_Head/emapItem/emap
XML_Head/emapItem/emap/Info
XML_Head/emapItem/emap/Info
XML_Head/emapItem/emap/Info
...
可能就是要抓每個 Info 標籤裡的東西。
若要更詳細可以:
$ xml el -a o.xml
XML_Head
XML_Head/@version
XML_Head/@status
XML_Head/@total
XML_Head/emapItem
XML_Head/emapItem/emap
XML_Head/emapItem/emap/Info
XML_Head/emapItem/emap/Info/@groupTypeName
XML_Head/emapItem/emap/Info/@mainTypeName
XML_Head/emapItem/emap/Info/@mainTypePk
XML_Head/emapItem/emap/Info/@name
XML_Head/emapItem/emap/Info/@representImage
XML_Head/emapItem/emap/Info/@intro
XML_Head/emapItem/emap/Info/@areaCode
XML_Head/emapItem/emap/Info/@cityName
XML_Head/emapItem/emap/Info/@address
XML_Head/emapItem/emap/Info/@longitude
XML_Head/emapItem/emap/Info/@latitude
XML_Head/emapItem/emap/Info/@buildingYearName
XML_Head/emapItem/emap/Info/@author
XML_Head/emapItem/emap/Info/@size
XML_Head/emapItem/emap/Info/@material
...
連想要抓的 @name 都辨識得到,要把該值抓出應就在眼前了…
接下來就應是怎麼query所要的內容。
XML的 select
查詢有幾個要抓的 Info 的元素?
$ xml sel -t -v "count(XML_Head/emapItem/emap/Info)" o.xml
2247
再用這個指令,就把所有name的值抓到了:
$ xml sel -t -m /XML_Head/emapItem/emap/Info -v "concat(@name,'')" -n o.xml|less
聚沙成塔 Accumulating much from a little
所拾 Key
深耕.生根 Plowing and rooting
生命的禮讚 The praise of life
大橢圓
飛行船
珍愛一生(1)
珍愛一生(2)
..
如果要把其他值一起抓出,變成csv格式:
$ xml sel -t -m /XML_Head/emapItem/emap/Info -v "concat(@name,'|',@author)" -n o.xml|less
聚沙成塔 Accumulating much from a little|林舜龍、楊仁明、張明風 lin Shuen-Long, Yang Jen-Ming, Chang Ming-Feng
所拾 Key|廖秀玲 Liao Xiu-Ling
深耕.生根 Plowing and rooting|邱泰洋 Ciou Tai-Yang
生命的禮讚 The praise of life|王振瑋 Wang Chen-Wei
大橢圓|赫穌斯•拉斐爾•索托(Jesus Rafael Soto)
飛行船|王為河
珍愛一生(1)|盧明德、郭挹芬
珍愛一生(2)|盧明德、郭挹芬
林間上翔|盧明德、郭挹芬
這樣就完工了,若要其他的值,就在 contact 裡繼續加所要的欄位。
參考資料:
XMLStarlet Command Line XML Toolkit
XMLStarlet 使用入门
XmlStarlet Command Line XML Toolkit User's Guide
How to indent html with xmllint?
XML formatting Indentation Tags Matching - Linux