有時候會想要對網頁檔或 xml 檔 (例如 svg 或 gpx) 做批次編輯, 比方說想把一堆 <li> 元素變成表格的 <tr> 元素 (當然也要同時把每一條的內文拆好幾個 <td> 欄位等等)。 regexp 處理文字檔很方便; 但是遇到 xml/html 就弱掉了。 正確的做法是採用 xpath 跟 xslt。 如果想做的是比較簡單的處理, 那麼可以用 xmlstarlet 這個命令列工具。
[2024/5/20] 如果只是查詢某些欄位, 改推 xq 簡單很多!
首先請安裝 xmlstarlet: apt-get install xmlstarlet
並且下載
extract.php。
範例題目是這樣的: 我想找 「西班牙文-英文」 字典, 而且只要很簡單的文字對照表就好, 不要 app。 找到很讚的 First 5000 words of Spanish。 目標是要用命令列處理每一頁, 然後把它全部串成一個簡單的 table。
- 抓下一個頁面:
wget -O 02.html http://www.memrise.com/course/737/first-5000-words-of-spanish-2/2/
- 頁面標籤太亂太複雜了, 等一下如果直接用 xmlstarlet 處理,
可能會卡紙。 先用 tidy 或 extract.php 整理簡化:
extract.php -s '.central-column' < 02.html > a.html
或tidy 02.html < a.html
- 擷取出西班牙文欄位 (class="col_a ...") 跟英文欄位
(class="col_b ..."):
xmlstarlet sel -B -t -c '//div[contains(@class,"col_a") or contains(@class,"col_b")]' a.html > b.html
- 假設先前是採用 extract.php 而不是 tidy,
那麼會看到所有 <div> 黏在一起, 當中沒有換列。
幫它插入一些換列:
perl -pe 's#</div><div#</div>\n<div#g' b.html > c.html
- 把 <div> 轉成 <tr> 跟 <td>
並且把多餘的標籤都刪掉:
perl -pe 's#<div class="col_a.*?>#<tr>#; s#<div class="col_b.*?">##; s#<div class="text">#<td>#; s#</div>##g' c.html > d.html
xmlstarlet 的教學文很難找: 使用者手冊 勉強算是教學文; 其他還有 1、 2、 XML 轉 csv 範例。
遇到問題, 如果用 xmlstarlet 當關鍵詞下去搜尋, 只有比較簡單的問題找得到答案 -- 例如篩選出某些元素, 個別逐一 改名、 刪元素、 改屬性、 ...。 以上類型的問題, 學習 基本的 xpath 語法 應該會很有幫助。 若是複雜的問題, 改用 xpath 加上問題關鍵字下去搜尋比較容易找得到答案 -- 例如搬動或複製元素, 需要第二個參數來指定目的地的運算。 但找到的答案通常叫你直接寫 xslt。 例如最後這一步本來希望也用 xmlstarlet 做; 但浪費了好幾小時還是沒研究出來該如何把一個 node 跟它的兄弟包在一起。 (上面每一對 「西文-英文」 組。) 最後還是用 regexp 比較簡單。
另一個類似的工具是 xml-coreutils。 作者詳細解釋設計理念。
其實我試著要學 xmlstarlet 已經兩三次了, 一直想把它拿來當成 「專門對付 xml 檔的強化版 regexp」 來用; 但每次都卡關, 所以一直沒寫心得。 看起來不是我太弱就是它真的不太好用。 我應該別再撐了, 直接學 xslt 算了嗎? 那不如用 querypath 寫程式還更自由更簡單呢!
分享 : beautifulsoup
回覆刪除